home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / _archvrs / unix / tar_1_11.sha < prev    next >
Text File  |  1994-01-23  |  792KB  |  27,662 lines

  1. #! /bin/sh
  2. # This is a shell archive.  Remove anything before this line, then unpack
  3. # it by saving it into a file and typing "sh file".  To overwrite existing
  4. # files, type "sh file -c".  You can also feed this as standard input via
  5. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  6. # will see the following message at the end:
  7. #        "End of shell archive."
  8. # Contents:  tar.c create.c extract.c buffer.c getoldopt.c update.c
  9. #   gnu.c mangle.c version.c list.c names.c diffarch.c port.c
  10. #   fnmatch.c getopt.c malloc.c getopt1.c regex.c getdate.y getdate.c
  11. #   alloca.c README INSTALL NEWS COPYING ChangeLog Makefile.in
  12. #   makefile.pc configure configure.in tar.h fnmatch.h pathmax.h
  13. #   port.h open3.h getopt.h regex.h rmt.h rmt.c rtapelib.c msd_dir.h
  14. #   msd_dir.c tcexparg.c level-0 level-1 backup-specs dump-remind
  15. #   testpad.c getpagesize.h
  16. # Wrapped by mib@geech.gnu.ai.mit.edu on Thu Mar 25 14:01:53 1993
  17. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  18. if test -f 'tar.c' -a "${1}" != "-c" ; then 
  19.   echo shar: Will not clobber existing file \"'tar.c'\"
  20. else
  21. echo shar: Extracting \"'tar.c'\" \(36191 characters\)
  22. sed "s/^X//" >'tar.c' <<'END_OF_FILE'
  23. X/* Tar -- a tape archiver.
  24. X   Copyright (C) 1988, 1992, 1993 Free Software Foundation
  25. X
  26. XThis file is part of GNU Tar.
  27. X
  28. XGNU Tar is free software; you can redistribute it and/or modify
  29. Xit under the terms of the GNU General Public License as published by
  30. Xthe Free Software Foundation; either version 2, or (at your option)
  31. Xany later version.
  32. X
  33. XGNU Tar is distributed in the hope that it will be useful,
  34. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  35. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  36. XGNU General Public License for more details.
  37. X
  38. XYou should have received a copy of the GNU General Public License
  39. Xalong with GNU Tar; see the file COPYING.  If not, write to
  40. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  41. X
  42. X/*
  43. X * A tar (tape archiver) program.
  44. X *
  45. X * Written by John Gilmore, ihnp4!hoptoad!gnu, starting 25 Aug 85.
  46. X */
  47. X
  48. X#include <stdio.h>
  49. X#include <sys/types.h>        /* Needed for typedefs in tar.h */
  50. X#include "getopt.h"
  51. X#include "regex.h"
  52. X
  53. X/*
  54. X * The following causes "tar.h" to produce definitions of all the
  55. X * global variables, rather than just "extern" declarations of them.
  56. X */
  57. X#define TAR_EXTERN        /**/
  58. X#include "tar.h"
  59. X
  60. X#include "port.h"
  61. X#include "fnmatch.h"
  62. X
  63. X/*
  64. X * We should use a conversion routine that does reasonable error
  65. X * checking -- atoi doesn't.  For now, punt.  FIXME.
  66. X */
  67. X#define intconv    atoi
  68. XPTR ck_malloc ();
  69. XPTR ck_realloc ();
  70. Xextern int getoldopt ();
  71. Xextern void read_and ();
  72. Xextern void list_archive ();
  73. Xextern void extract_archive ();
  74. Xextern void diff_archive ();
  75. Xextern void create_archive ();
  76. Xextern void update_archive ();
  77. Xextern void junk_archive ();
  78. Xextern void init_volume_number ();
  79. Xextern void closeout_volume_number ();
  80. X
  81. X/* JF */
  82. Xextern time_t get_date ();
  83. X
  84. Xtime_t new_time;
  85. X
  86. Xstatic FILE *namef;        /* File to read names from */
  87. Xstatic char **n_argv;        /* Argv used by name routines */
  88. Xstatic int n_argc;        /* Argc used by name routines */
  89. Xstatic char **n_ind;        /* Store an array of names */
  90. Xstatic int n_indalloc;        /* How big is the array? */
  91. Xstatic int n_indused;        /* How many entries does it have? */
  92. Xstatic int n_indscan;        /* How many of the entries have we scanned? */
  93. X
  94. X
  95. Xextern FILE *msg_file;
  96. X
  97. Xint check_exclude ();
  98. Xvoid add_exclude ();
  99. Xvoid add_exclude_file ();
  100. Xvoid addname ();
  101. Xvoid describe ();
  102. Xvoid diff_init ();
  103. Xvoid extr_init ();
  104. Xint is_regex ();
  105. Xvoid name_add ();
  106. Xvoid name_init ();
  107. Xvoid options ();
  108. Xchar *un_quote_string ();
  109. X
  110. X#ifndef S_ISLNK
  111. X#define lstat stat
  112. X#endif
  113. X
  114. X#ifndef DEFBLOCKING
  115. X#define DEFBLOCKING 20
  116. X#endif
  117. X
  118. X#ifndef DEF_AR_FILE
  119. X#define DEF_AR_FILE "tar.out"
  120. X#endif
  121. X
  122. X/* For long options that unconditionally set a single flag, we have getopt
  123. X   do it.  For the others, we share the code for the equivalent short
  124. X   named option, the name of which is stored in the otherwise-unused `val'
  125. X   field of the `struct option'; for long options that have no equivalent
  126. X   short option, we use nongraphic characters as pseudo short option
  127. X   characters, starting (for no particular reason) with character 10. */
  128. X
  129. Xstruct option long_options[] =
  130. X{
  131. X  {"create", 0, 0, 'c'},
  132. X  {"append", 0, 0, 'r'},
  133. X  {"extract", 0, 0, 'x'},
  134. X  {"get", 0, 0, 'x'},
  135. X  {"list", 0, 0, 't'},
  136. X  {"update", 0, 0, 'u'},
  137. X  {"catenate", 0, 0, 'A'},
  138. X  {"concatenate", 0, 0, 'A'},
  139. X  {"compare", 0, 0, 'd'},
  140. X  {"diff", 0, 0, 'd'},
  141. X  {"delete", 0, 0, 14},
  142. X  {"help", 0, 0, 12},
  143. X
  144. X  {"null", 0, 0, 16},
  145. X  {"directory", 1, 0, 'C'},
  146. X  {"record-number", 0, &f_sayblock, 1},
  147. X  {"files-from", 1, 0, 'T'},
  148. X  {"label", 1, 0, 'V'},
  149. X  {"exclude-from", 1, 0, 'X'},
  150. X  {"exclude", 1, 0, 15},
  151. X  {"file", 1, 0, 'f'},
  152. X  {"block-size", 1, 0, 'b'},
  153. X  {"version", 0, 0, 11},
  154. X  {"verbose", 0, 0, 'v'},
  155. X  {"totals", 0, &f_totals, 1},
  156. X
  157. X  {"read-full-blocks", 0, &f_reblock, 1},
  158. X  {"starting-file", 1, 0, 'K'},
  159. X  {"to-stdout", 0, &f_exstdout, 1},
  160. X  {"ignore-zeros", 0, &f_ignorez, 1},
  161. X  {"keep-old-files", 0, 0, 'k'},
  162. X  {"same-permissions", 0, &f_use_protection, 1},
  163. X  {"preserve-permissions", 0, &f_use_protection, 1},
  164. X  {"modification-time", 0, &f_modified, 1},
  165. X  {"preserve", 0, 0, 10},
  166. X  {"same-order", 0, &f_sorted_names, 1},
  167. X  {"same-owner", 0, &f_do_chown, 1},
  168. X  {"preserve-order", 0, &f_sorted_names, 1},
  169. X
  170. X  {"newer", 1, 0, 'N'},
  171. X  {"after-date", 1, 0, 'N'},
  172. X  {"newer-mtime", 1, 0, 13},
  173. X  {"incremental", 0, 0, 'G'},
  174. X  {"listed-incremental", 1, 0, 'g'},
  175. X  {"multi-volume", 0, &f_multivol, 1},
  176. X  {"info-script", 1, 0, 'F'},
  177. X  {"new-volume-script", 1, 0, 'F'},
  178. X  {"absolute-paths", 0, &f_absolute_paths, 1},
  179. X  {"interactive", 0, &f_confirm, 1},
  180. X  {"confirmation", 0, &f_confirm, 1},
  181. X
  182. X  {"verify", 0, &f_verify, 1},
  183. X  {"dereference", 0, &f_follow_links, 1},
  184. X  {"one-file-system", 0, &f_local_filesys, 1},
  185. X  {"old-archive", 0, 0, 'o'},
  186. X  {"portability", 0, 0, 'o'},
  187. X  {"compress", 0, 0, 'Z'},
  188. X  {"uncompress", 0, 0, 'Z'},
  189. X  {"block-compress", 0, &f_compress_block, 1},
  190. X  {"gzip", 0, 0, 'z'},
  191. X  {"ungzip", 0, 0, 'z'},
  192. X  {"use-compress-program", 1, 0, 18},
  193. X    
  194. X
  195. X  {"same-permissions", 0, &f_use_protection, 1},
  196. X  {"sparse", 0, &f_sparse_files, 1},
  197. X  {"tape-length", 1, 0, 'L'},
  198. X  {"remove-files", 0, &f_remove_files, 1},
  199. X  {"ignore-failed-read", 0, &f_ignore_failed_read, 1},
  200. X  {"checkpoint", 0, &f_checkpoint, 1},
  201. X  {"show-omitted-dirs", 0, &f_show_omitted_dirs, 1},
  202. X  {"volno-file", 1, 0, 17},
  203. X  {"force-local", 0, &f_force_local, 1},
  204. X  {"atime-preserve", 0, &f_atime_preserve, 1},
  205. X
  206. X  {0, 0, 0, 0}
  207. X};
  208. X
  209. X/*
  210. X * Main routine for tar.
  211. X */
  212. Xvoid
  213. Xmain (argc, argv)
  214. X     int argc;
  215. X     char **argv;
  216. X{
  217. X  extern char version_string[];
  218. X
  219. X  tar = argv[0];        /* JF: was "tar" Set program name */
  220. X  filename_terminator = '\n';
  221. X  errors = 0;
  222. X
  223. X  options (argc, argv);
  224. X
  225. X  if (!n_argv)
  226. X    name_init (argc, argv);
  227. X
  228. X  if (f_volno_file)
  229. X    init_volume_number ();
  230. X
  231. X  switch (cmd_mode)
  232. X    {
  233. X    case CMD_CAT:
  234. X    case CMD_UPDATE:
  235. X    case CMD_APPEND:
  236. X      update_archive ();
  237. X      break;
  238. X    case CMD_DELETE:
  239. X      junk_archive ();
  240. X      break;
  241. X    case CMD_CREATE:
  242. X      create_archive ();
  243. X      if (f_totals)
  244. X    fprintf (stderr, "Total bytes written: %d\n", tot_written);
  245. X      break;
  246. X    case CMD_EXTRACT:
  247. X      if (f_volhdr)
  248. X    {
  249. X      const char *err;
  250. X      label_pattern = (struct re_pattern_buffer *)
  251. X        ck_malloc (sizeof *label_pattern);
  252. X      err = re_compile_pattern (f_volhdr, strlen (f_volhdr),
  253. X                    label_pattern);
  254. X      if (err)
  255. X        {
  256. X          fprintf (stderr, "Bad regular expression: %s\n",
  257. X               err);
  258. X          errors++;
  259. X          break;
  260. X        }
  261. X
  262. X    }
  263. X      extr_init ();
  264. X      read_and (extract_archive);
  265. X      break;
  266. X    case CMD_LIST:
  267. X      if (f_volhdr)
  268. X    {
  269. X      const char *err;
  270. X      label_pattern = (struct re_pattern_buffer *)
  271. X        ck_malloc (sizeof *label_pattern);
  272. X      err = re_compile_pattern (f_volhdr, strlen (f_volhdr),
  273. X                    label_pattern);
  274. X      if (err)
  275. X        {
  276. X          fprintf (stderr, "Bad regular expression: %s\n",
  277. X               err);
  278. X          errors++;
  279. X          break;
  280. X        }
  281. X    }
  282. X      read_and (list_archive);
  283. X#if 0
  284. X      if (!errors)
  285. X    errors = different;
  286. X#endif
  287. X      break;
  288. X    case CMD_DIFF:
  289. X      diff_init ();
  290. X      read_and (diff_archive);
  291. X      break;
  292. X    case CMD_VERSION:
  293. X      fprintf (stderr, "%s\n", version_string);
  294. X      break;
  295. X    case CMD_NONE:
  296. X      msg ("you must specify exactly one of the r, c, t, x, or d options\n");
  297. X      fprintf (stderr, "For more information, type ``%s --help''.\n", tar);
  298. X      exit (EX_ARGSBAD);
  299. X    }
  300. X  if (f_volno_file)
  301. X    closeout_volume_number ();
  302. X  exit (errors);
  303. X  /* NOTREACHED */
  304. X}
  305. X
  306. X
  307. X/*
  308. X * Parse the options for tar.
  309. X */
  310. Xvoid
  311. Xoptions (argc, argv)
  312. X     int argc;
  313. X     char **argv;
  314. X{
  315. X  register int c;        /* Option letter */
  316. X  int ind = -1;
  317. X
  318. X  /* Set default option values */
  319. X  blocking = DEFBLOCKING;    /* From Makefile */
  320. X  ar_files = (char **) ck_malloc (sizeof (char *) * 10);
  321. X  ar_files_len = 10;
  322. X  n_ar_files = 0;
  323. X  cur_ar_file = 0;
  324. X
  325. X  /* Parse options */
  326. X  while ((c = getoldopt (argc, argv,
  327. X           "-01234567Ab:BcC:df:F:g:GhikK:lL:mMN:oOpPrRsStT:uvV:wWxX:zZ",
  328. X             long_options, &ind)) != EOF)
  329. X    {
  330. X      switch (c)
  331. X    {
  332. X    case 0:        /* long options that set a single flag */
  333. X      break;
  334. X    case 1:
  335. X      /* File name or non-parsed option */
  336. X      name_add (optarg);
  337. X      break;
  338. X    case 'C':
  339. X      name_add ("-C");
  340. X      name_add (optarg);
  341. X      break;
  342. X    case 10:        /* preserve */
  343. X      f_use_protection = f_sorted_names = 1;
  344. X      break;
  345. X    case 11:
  346. X      if (cmd_mode != CMD_NONE)
  347. X        goto badopt;
  348. X      cmd_mode = CMD_VERSION;
  349. X      break;
  350. X    case 12:        /* help */
  351. X      printf ("This is GNU tar, the tape archiving program.\n");
  352. X      describe ();
  353. X      exit (1);
  354. X    case 13:
  355. X      f_new_files++;
  356. X      goto get_newer;
  357. X
  358. X    case 14:        /* Delete in the archive */
  359. X      if (cmd_mode != CMD_NONE)
  360. X        goto badopt;
  361. X      cmd_mode = CMD_DELETE;
  362. X      break;
  363. X
  364. X    case 15:
  365. X      f_exclude++;
  366. X      add_exclude (optarg);
  367. X      break;
  368. X
  369. X    case 16:        /* -T reads null terminated filenames. */
  370. X      filename_terminator = '\0';
  371. X      break;
  372. X
  373. X    case 17:
  374. X      f_volno_file = optarg;
  375. X      break;
  376. X
  377. X    case 18:
  378. X      if (f_compressprog)
  379. X        {
  380. X          msg ("Only one compression option permitted\n");
  381. X          exit (EX_ARGSBAD);
  382. X        }
  383. X      f_compressprog = optarg;
  384. X      break;
  385. X
  386. X    case 'g':        /* We are making a GNU dump; save
  387. X                   directories at the beginning of
  388. X                   the archive, and include in each
  389. X                   directory its contents */
  390. X      if (f_oldarch)
  391. X        goto badopt;
  392. X      f_gnudump++;
  393. X      gnu_dumpfile = optarg;
  394. X      break;
  395. X
  396. X
  397. X    case '0':
  398. X    case '1':
  399. X    case '2':
  400. X    case '3':
  401. X    case '4':
  402. X    case '5':
  403. X    case '6':
  404. X    case '7':
  405. X      {
  406. X        /* JF this'll have to be modified for other
  407. X                   systems, of course! */
  408. X        int d, add;
  409. X        static char buf[50];
  410. X
  411. X        d = getoldopt (argc, argv, "lmh");
  412. X#ifdef MAYBEDEF
  413. X        sprintf (buf, "/dev/rmt/%d%c", c, d);
  414. X#else
  415. X#ifndef LOW_NUM
  416. X#define LOW_NUM 0
  417. X#define MID_NUM 8
  418. X#define HGH_NUM 16
  419. X#endif
  420. X        if (d == 'l')
  421. X          add = LOW_NUM;
  422. X        else if (d == 'm')
  423. X          add = MID_NUM;
  424. X        else if (d == 'h')
  425. X          add = HGH_NUM;
  426. X        else
  427. X          goto badopt;
  428. X
  429. X        sprintf (buf, "/dev/rmt%d", add + c - '0');
  430. X#endif
  431. X        if (n_ar_files == ar_files_len)
  432. X          ar_files
  433. X        = (char **)
  434. X        ck_malloc (sizeof (char *)
  435. X               * (ar_files_len *= 2));
  436. X        ar_files[n_ar_files++] = buf;
  437. X      }
  438. X      break;
  439. X
  440. X    case 'A':        /* Arguments are tar files,
  441. X                   just cat them onto the end
  442. X                   of the archive.  */
  443. X      if (cmd_mode != CMD_NONE)
  444. X        goto badopt;
  445. X      cmd_mode = CMD_CAT;
  446. X      break;
  447. X
  448. X    case 'b':        /* Set blocking factor */
  449. X      blocking = intconv (optarg);
  450. X      break;
  451. X
  452. X    case 'B':        /* Try to reblock input */
  453. X      f_reblock++;        /* For reading 4.2BSD pipes */
  454. X      break;
  455. X
  456. X    case 'c':        /* Create an archive */
  457. X      if (cmd_mode != CMD_NONE)
  458. X        goto badopt;
  459. X      cmd_mode = CMD_CREATE;
  460. X      break;
  461. X
  462. X#if 0
  463. X    case 'C':
  464. X      if (chdir (optarg) < 0)
  465. X        msg_perror ("Can't change directory to %d", optarg);
  466. X      break;
  467. X#endif
  468. X
  469. X    case 'd':        /* Find difference tape/disk */
  470. X      if (cmd_mode != CMD_NONE)
  471. X        goto badopt;
  472. X      cmd_mode = CMD_DIFF;
  473. X      break;
  474. X
  475. X    case 'f':        /* Use ar_file for the archive */
  476. X      if (n_ar_files == ar_files_len)
  477. X        ar_files
  478. X          = (char **) ck_malloc (sizeof (char *)
  479. X                     * (ar_files_len *= 2));
  480. X
  481. X      ar_files[n_ar_files++] = optarg;
  482. X      break;
  483. X
  484. X    case 'F':
  485. X      /* Since -F is only useful with -M , make it implied */
  486. X      f_run_script_at_end++;/* run this script at the end */
  487. X      info_script = optarg;    /* of each tape */
  488. X      f_multivol++;
  489. X      break;
  490. X
  491. X    case 'G':        /* We are making a GNU dump; save
  492. X                   directories at the beginning of
  493. X                   the archive, and include in each
  494. X                   directory its contents */
  495. X      if (f_oldarch)
  496. X        goto badopt;
  497. X      f_gnudump++;
  498. X      gnu_dumpfile = 0;
  499. X      break;
  500. X
  501. X    case 'h':
  502. X      f_follow_links++;    /* follow symbolic links */
  503. X      break;
  504. X
  505. X    case 'i':
  506. X      f_ignorez++;        /* Ignore zero records (eofs) */
  507. X      /*
  508. X             * This can't be the default, because Unix tar
  509. X             * writes two records of zeros, then pads out the
  510. X             * block with garbage.
  511. X             */
  512. X      break;
  513. X
  514. X    case 'k':        /* Don't overwrite files */
  515. X#ifdef NO_OPEN3
  516. X      msg ("can't keep old files on this system");
  517. X      exit (EX_ARGSBAD);
  518. X#else
  519. X      f_keep++;
  520. X#endif
  521. X      break;
  522. X
  523. X    case 'K':
  524. X      f_startfile++;
  525. X      addname (optarg);
  526. X      break;
  527. X
  528. X    case 'l':        /* When dumping directories, don't
  529. X                   dump files/subdirectories that are
  530. X                   on other filesystems. */
  531. X      f_local_filesys++;
  532. X      break;
  533. X
  534. X    case 'L':
  535. X      tape_length = intconv (optarg);
  536. X      f_multivol++;
  537. X      break;
  538. X    case 'm':
  539. X      f_modified++;
  540. X      break;
  541. X
  542. X    case 'M':        /* Make Multivolume archive:
  543. X                   When we can't write any more
  544. X                   into the archive, re-open it,
  545. X                   and continue writing */
  546. X      f_multivol++;
  547. X      break;
  548. X
  549. X    case 'N':        /* Only write files newer than X */
  550. X    get_newer:
  551. X      f_new_files++;
  552. X      new_time = get_date (optarg, (PTR) 0);
  553. X      if (new_time == (time_t) - 1)
  554. X        {
  555. X          msg ("invalid date format `%s'", optarg);
  556. X          exit (EX_ARGSBAD);
  557. X        }
  558. X      break;
  559. X
  560. X    case 'o':        /* Generate old archive */
  561. X      if (f_gnudump /* || f_dironly */ )
  562. X        goto badopt;
  563. X      f_oldarch++;
  564. X      break;
  565. X
  566. X    case 'O':
  567. X      f_exstdout++;
  568. X      break;
  569. X
  570. X    case 'p':
  571. X      f_use_protection++;
  572. X      break;
  573. X
  574. X    case 'P':
  575. X      f_absolute_paths++;
  576. X      break;
  577. X
  578. X    case 'r':        /* Append files to the archive */
  579. X      if (cmd_mode != CMD_NONE)
  580. X        goto badopt;
  581. X      cmd_mode = CMD_APPEND;
  582. X      break;
  583. X
  584. X    case 'R':
  585. X      f_sayblock++;        /* Print block #s for debug */
  586. X      break;        /* of bad tar archives */
  587. X
  588. X    case 's':
  589. X      f_sorted_names++;    /* Names to extr are sorted */
  590. X      break;
  591. X
  592. X    case 'S':        /* deal with sparse files */
  593. X      f_sparse_files++;
  594. X      break;
  595. X    case 't':
  596. X      if (cmd_mode != CMD_NONE)
  597. X        goto badopt;
  598. X      cmd_mode = CMD_LIST;
  599. X      f_verbose++;        /* "t" output == "cv" or "xv" */
  600. X      break;
  601. X
  602. X    case 'T':
  603. X      name_file = optarg;
  604. X      f_namefile++;
  605. X      break;
  606. X
  607. X    case 'u':        /* Append files to the archive that
  608. X                   aren't there, or are newer than the
  609. X                   copy in the archive */
  610. X      if (cmd_mode != CMD_NONE)
  611. X        goto badopt;
  612. X      cmd_mode = CMD_UPDATE;
  613. X      break;
  614. X
  615. X    case 'v':
  616. X      f_verbose++;
  617. X      break;
  618. X
  619. X    case 'V':
  620. X      f_volhdr = optarg;
  621. X      break;
  622. X
  623. X    case 'w':
  624. X      f_confirm++;
  625. X      break;
  626. X
  627. X    case 'W':
  628. X      f_verify++;
  629. X      break;
  630. X
  631. X    case 'x':        /* Extract files from the archive */
  632. X      if (cmd_mode != CMD_NONE)
  633. X        goto badopt;
  634. X      cmd_mode = CMD_EXTRACT;
  635. X      break;
  636. X
  637. X    case 'X':
  638. X      f_exclude++;
  639. X      add_exclude_file (optarg);
  640. X      break;
  641. X
  642. X    case 'z':
  643. X      if (f_compressprog)
  644. X        {
  645. X          msg ("Only one compression option permitted\n");
  646. X          exit (EX_ARGSBAD);
  647. X        }
  648. X      f_compressprog = "gzip";
  649. X      break;
  650. X
  651. X    case 'Z':
  652. X      if (f_compressprog)
  653. X        {
  654. X          msg ("Only one compression option permitted\n");
  655. X          exit (EX_ARGSBAD);
  656. X        }
  657. X      f_compressprog = "compress";
  658. X      break;
  659. X
  660. X    case '?':
  661. X    badopt:
  662. X      msg ("Unknown option.  Use '%s --help' for a complete list of options.", tar);
  663. X      exit (EX_ARGSBAD);
  664. X
  665. X    }
  666. X    }
  667. X
  668. X  blocksize = blocking * RECORDSIZE;
  669. X  if (n_ar_files == 0)
  670. X    {
  671. X      n_ar_files = 1;
  672. X      ar_files[0] = getenv ("TAPE");    /* From environment, or */
  673. X      if (ar_files[0] == 0)
  674. X    ar_files[0] = DEF_AR_FILE;    /* From Makefile */
  675. X    }
  676. X  if (n_ar_files > 1 && !f_multivol)
  677. X    {
  678. X      msg ("Multiple archive files requires --multi-volume\n");
  679. X      exit (EX_ARGSBAD);
  680. X    }
  681. X  if (f_compress_block && !f_compressprog)
  682. X    {
  683. X      msg ("You must use a compression option (--gzip, --compress\n\
  684. Xor --use-compress-program) with --block-compress.\n");
  685. X      exit (EX_ARGSBAD);
  686. X    }
  687. X}
  688. X
  689. X
  690. X/*
  691. X * Print as much help as the user's gonna get.
  692. X *
  693. X * We have to sprinkle in the KLUDGE lines because too many compilers
  694. X * cannot handle character strings longer than about 512 bytes.  Yuk!
  695. X * In particular, MS-DOS and Xenix MSC and PDP-11 V7 Unix have this
  696. X * problem.
  697. X */
  698. Xvoid
  699. Xdescribe ()
  700. X{
  701. X  puts ("choose one of the following:");
  702. X  fputs ("\
  703. X-A, --catenate,\n\
  704. X    --concatenate    append tar files to an archive\n\
  705. X-c, --create        create a new archive\n\
  706. X-d, --diff,\n\
  707. X    --compare        find differences between archive and file system\n\
  708. X--delete        delete from the archive (not for use on mag tapes!)\n\
  709. X-r, --append        append files to the end of an archive\n\
  710. X-t, --list        list the contents of an archive\n\
  711. X-u, --update        only append files that are newer than copy in archive\n\
  712. X-x, --extract,\n\
  713. X    --get        extract files from an archive\n", stdout);
  714. X
  715. X  fprintf (stdout, "\
  716. XOther options:\n\
  717. X--atime-preserve    don't change access times on dumped files\n\
  718. X-b, --block-size N    block size of Nx512 bytes (default N=%d)\n", DEFBLOCKING);
  719. X  fputs ("\
  720. X-B, --read-full-blocks    reblock as we read (for reading 4.2BSD pipes)\n\
  721. X-C, --directory DIR    change to directory DIR\n\
  722. X--checkpoint        print directory names while reading the archive\n\
  723. X", stdout);            /* KLUDGE */
  724. X  fprintf (stdout, "\
  725. X-f, --file [HOSTNAME:]F    use archive file or device F (default %s)\n",
  726. X       DEF_AR_FILE);
  727. X  fputs ("\
  728. X--force-local        archive file is local even if has a colon\n\
  729. X-F, --info-script F\n\
  730. X    --new-volume-script F run script at end of each tape (implies -M)\n\
  731. X-G, --incremental    create/list/extract old GNU-format incremental backup\n\
  732. X-g, --listed-incremental F create/list/extract new GNU-format incremental backup\n\
  733. X-h, --dereference    don't dump symlinks; dump the files they point to\n\
  734. X-i, --ignore-zeros    ignore blocks of zeros in archive (normally mean EOF)\n\
  735. X--ignore-failed-read    don't exit with non-zero status on unreadable files\n\
  736. X-k, --keep-old-files    keep existing files; don't overwrite them from archive\n\
  737. X-K, --starting-file F    begin at file F in the archive\n\
  738. X-l, --one-file-system    stay in local file system when creating an archive\n\
  739. X-L, --tape-length N    change tapes after writing N*1024 bytes\n\
  740. X", stdout);            /* KLUDGE */
  741. X  fputs ("\
  742. X-m, --modification-time    don't extract file modified time\n\
  743. X-M, --multi-volume    create/list/extract multi-volume archive\n\
  744. X-N, --after-date DATE,\n\
  745. X    --newer DATE    only store files newer than DATE\n\
  746. X-o, --old-archive,\n\
  747. X    --portability    write a V7 format archive, rather than ANSI format\n\
  748. X-O, --to-stdout        extract files to standard output\n\
  749. X-p, --same-permissions,\n\
  750. X    --preserve-permissions extract all protection information\n\
  751. X-P, --absolute-paths    don't strip leading `/'s from file names\n\
  752. X--preserve        like -p -s\n\
  753. X", stdout);            /* KLUDGE */
  754. X  fputs ("\
  755. X-R, --record-number    show record number within archive with each message\n\
  756. X--remove-files        remove files after adding them to the archive\n\
  757. X-s, --same-order,\n\
  758. X    --preserve-order    list of names to extract is sorted to match archive\n\
  759. X--same-owner        create extracted files with the same ownership \n\
  760. X-S, --sparse        handle sparse files efficiently\n\
  761. X-T, --files-from F    get names to extract or create from file F\n\
  762. X--null            -T reads null-terminated names, disable -C\n\
  763. X--totals        print total bytes written with --create\n\
  764. X-v, --verbose        verbosely list files processed\n\
  765. X-V, --label NAME    create archive with volume name NAME\n\
  766. X--version        print tar program version number\n\
  767. X-w, --interactive,\n\
  768. X    --confirmation    ask for confirmation for every action\n\
  769. X", stdout);            /* KLUDGE */
  770. X  fputs ("\
  771. X-W, --verify        attempt to verify the archive after writing it\n\
  772. X--exclude FILE        exclude file FILE\n\
  773. X-X, --exclude-from FILE    exclude files listed in FILE\n\
  774. X-Z, --compress,\n\
  775. X    --uncompress          filter the archive through compress\n\
  776. X-z, --gzip,\n\
  777. X    --ungzip        filter the archive through gzip\n\
  778. X--use-compress-program PROG\n\
  779. X            filter the archive through PROG (which must accept -d)\n\
  780. X--block-compress    block the output of compression program for tapes\n\
  781. X-[0-7][lmh]        specify drive and density\n\
  782. X", stdout);
  783. X}
  784. X
  785. Xvoid
  786. Xname_add (name)
  787. X     char *name;
  788. X{
  789. X  if (n_indalloc == n_indused)
  790. X    {
  791. X      n_indalloc += 10;
  792. X      n_ind = (char **) (n_indused ? ck_realloc (n_ind, n_indalloc * sizeof (char *)): ck_malloc (n_indalloc * sizeof (char *)));
  793. X    }
  794. X  n_ind[n_indused++] = name;
  795. X}
  796. X
  797. X/*
  798. X * Set up to gather file names for tar.
  799. X *
  800. X * They can either come from stdin or from argv.
  801. X */
  802. Xvoid
  803. Xname_init (argc, argv)
  804. X     int argc;
  805. X     char **argv;
  806. X{
  807. X
  808. X  if (f_namefile)
  809. X    {
  810. X      if (optind < argc)
  811. X    {
  812. X      msg ("too many args with -T option");
  813. X      exit (EX_ARGSBAD);
  814. X    }
  815. X      if (!strcmp (name_file, "-"))
  816. X    {
  817. X      namef = stdin;
  818. X    }
  819. X      else
  820. X    {
  821. X      namef = fopen (name_file, "r");
  822. X      if (namef == NULL)
  823. X        {
  824. X          msg_perror ("can't open file %s", name_file);
  825. X          exit (EX_BADFILE);
  826. X        }
  827. X    }
  828. X    }
  829. X  else
  830. X    {
  831. X      /* Get file names from argv, after options. */
  832. X      n_argc = argc;
  833. X      n_argv = argv;
  834. X    }
  835. X}
  836. X
  837. X/* Read the next filename read from STREAM and null-terminate it.
  838. X   Put it into BUFFER, reallocating and adjusting *PBUFFER_SIZE if necessary.
  839. X   Return the new value for BUFFER, or NULL at end of file. */
  840. X
  841. Xchar *
  842. Xread_name_from_file (buffer, pbuffer_size, stream)
  843. X     char *buffer;
  844. X     size_t *pbuffer_size;
  845. X     FILE *stream;
  846. X{
  847. X  register int c;
  848. X  register int indx = 0;
  849. X  register size_t buffer_size = *pbuffer_size;
  850. X
  851. X  while ((c = getc (stream)) != EOF && c != filename_terminator)
  852. X    {
  853. X      if (indx == buffer_size)
  854. X    {
  855. X      buffer_size += NAMSIZ;
  856. X      buffer = ck_realloc (buffer, buffer_size + 2);
  857. X    }
  858. X      buffer[indx++] = c;
  859. X    }
  860. X  if (indx == 0 && c == EOF)
  861. X    return NULL;
  862. X  if (indx == buffer_size)
  863. X    {
  864. X      buffer_size += NAMSIZ;
  865. X      buffer = ck_realloc (buffer, buffer_size + 2);
  866. X    }
  867. X  buffer[indx] = '\0';
  868. X  *pbuffer_size = buffer_size;
  869. X  return buffer;
  870. X}
  871. X
  872. X/*
  873. X * Get the next name from argv or the name file.
  874. X *
  875. X * Result is in static storage and can't be relied upon across two calls.
  876. X *
  877. X * If CHANGE_DIRS is non-zero, treat a filename of the form "-C" as
  878. X * meaning that the next filename is the name of a directory to change to.
  879. X * If `filename_terminator' is '\0', CHANGE_DIRS is effectively always 0.
  880. X */
  881. X
  882. Xchar *
  883. Xname_next (change_dirs)
  884. X     int change_dirs;
  885. X{
  886. X  static char *buffer;        /* Holding pattern */
  887. X  static int buffer_siz;
  888. X  register char *p;
  889. X  register char *q = 0;
  890. X  register int next_name_is_dir = 0;
  891. X  extern char *un_quote_string ();
  892. X
  893. X  if (buffer_siz == 0)
  894. X    {
  895. X      buffer = ck_malloc (NAMSIZ + 2);
  896. X      buffer_siz = NAMSIZ;
  897. X    }
  898. X  if (filename_terminator == '\0')
  899. X    change_dirs = 0;
  900. Xtryagain:
  901. X  if (namef == NULL)
  902. X    {
  903. X      if (n_indscan < n_indused)
  904. X    p = n_ind[n_indscan++];
  905. X      else if (optind < n_argc)
  906. X    /* Names come from argv, after options */
  907. X    p = n_argv[optind++];
  908. X      else
  909. X    {
  910. X      if (q)
  911. X        msg ("Missing filename after -C");
  912. X      return NULL;
  913. X    }
  914. X
  915. X      /* JF trivial support for -C option.  I don't know if
  916. X           chdir'ing at this point is dangerous or not.
  917. X           It seems to work, which is all I ask. */
  918. X      if (change_dirs && !q && p[0] == '-' && p[1] == 'C' && p[2] == '\0')
  919. X    {
  920. X      q = p;
  921. X      goto tryagain;
  922. X    }
  923. X      if (q)
  924. X    {
  925. X      if (chdir (p) < 0)
  926. X        msg_perror ("Can't chdir to %s", p);
  927. X      q = 0;
  928. X      goto tryagain;
  929. X    }
  930. X      /* End of JF quick -C hack */
  931. X
  932. X#if 0
  933. X      if (f_exclude && check_exclude (p))
  934. X    goto tryagain;
  935. X#endif
  936. X      return un_quote_string (p);
  937. X    }
  938. X  while (p = read_name_from_file (buffer, &buffer_siz, namef))
  939. X    {
  940. X      buffer = p;
  941. X      if (*p == '\0')
  942. X    continue;        /* Ignore empty lines. */
  943. X      q = p + strlen (p) - 1;
  944. X      while (q > p && *q == '/')/* Zap trailing "/"s. */
  945. X    *q-- = '\0';
  946. X      if (change_dirs && next_name_is_dir == 0
  947. X      && p[0] == '-' && p[1] == 'C' && p[2] == '\0')
  948. X    {
  949. X      next_name_is_dir = 1;
  950. X      goto tryagain;
  951. X    }
  952. X      if (next_name_is_dir)
  953. X    {
  954. X      if (chdir (p) < 0)
  955. X        msg_perror ("Can't change to directory %s", p);
  956. X      next_name_is_dir = 0;
  957. X      goto tryagain;
  958. X    }
  959. X#if 0
  960. X      if (f_exclude && check_exclude (p))
  961. X    goto tryagain;
  962. X#endif
  963. X      return un_quote_string (p);
  964. X    }
  965. X  return NULL;
  966. X}
  967. X
  968. X
  969. X/*
  970. X * Close the name file, if any.
  971. X */
  972. Xvoid
  973. Xname_close ()
  974. X{
  975. X
  976. X  if (namef != NULL && namef != stdin)
  977. X    fclose (namef);
  978. X}
  979. X
  980. X
  981. X/*
  982. X * Gather names in a list for scanning.
  983. X * Could hash them later if we really care.
  984. X *
  985. X * If the names are already sorted to match the archive, we just
  986. X * read them one by one.  name_gather reads the first one, and it
  987. X * is called by name_match as appropriate to read the next ones.
  988. X * At EOF, the last name read is just left in the buffer.
  989. X * This option lets users of small machines extract an arbitrary
  990. X * number of files by doing "tar t" and editing down the list of files.
  991. X */
  992. Xvoid
  993. Xname_gather ()
  994. X{
  995. X  register char *p;
  996. X  static struct name *namebuf;    /* One-name buffer */
  997. X  static namelen;
  998. X  static char *chdir_name;
  999. X
  1000. X  if (f_sorted_names)
  1001. X    {
  1002. X      if (!namelen)
  1003. X    {
  1004. X      namelen = NAMSIZ;
  1005. X      namebuf = (struct name *) ck_malloc (sizeof (struct name) + NAMSIZ);
  1006. X    }
  1007. X      p = name_next (0);
  1008. X      if (p)
  1009. X    {
  1010. X      if (*p == '-' && p[1] == 'C' && p[2] == '\0')
  1011. X        {
  1012. X          chdir_name = name_next (0);
  1013. X          p = name_next (0);
  1014. X          if (!p)
  1015. X        {
  1016. X          msg ("Missing file name after -C");
  1017. X          exit (EX_ARGSBAD);
  1018. X        }
  1019. X          namebuf->change_dir = chdir_name;
  1020. X        }
  1021. X      namebuf->length = strlen (p);
  1022. X      if (namebuf->length >= namelen)
  1023. X        {
  1024. X          namebuf = (struct name *) ck_realloc (namebuf, sizeof (struct name) + namebuf->length);
  1025. X          namelen = namebuf->length;
  1026. X        }
  1027. X      strncpy (namebuf->name, p, namebuf->length);
  1028. X      namebuf->name[namebuf->length] = 0;
  1029. X      namebuf->next = (struct name *) NULL;
  1030. X      namebuf->found = 0;
  1031. X      namelist = namebuf;
  1032. X      namelast = namelist;
  1033. X    }
  1034. X      return;
  1035. X    }
  1036. X
  1037. X  /* Non sorted names -- read them all in */
  1038. X  while (p = name_next (0))
  1039. X    addname (p);
  1040. X}
  1041. X
  1042. X/*
  1043. X * Add a name to the namelist.
  1044. X */
  1045. Xvoid
  1046. Xaddname (name)
  1047. X     char *name;        /* pointer to name */
  1048. X{
  1049. X  register int i;        /* Length of string */
  1050. X  register struct name *p;    /* Current struct pointer */
  1051. X  static char *chdir_name;
  1052. X  char *new_name ();
  1053. X
  1054. X  if (name[0] == '-' && name[1] == 'C' && name[2] == '\0')
  1055. X    {
  1056. X      chdir_name = name_next (0);
  1057. X      name = name_next (0);
  1058. X      if (!chdir_name)
  1059. X    {
  1060. X      msg ("Missing file name after -C");
  1061. X      exit (EX_ARGSBAD);
  1062. X    }
  1063. X      if (chdir_name[0] != '/')
  1064. X    {
  1065. X      char *path = ck_malloc (PATH_MAX);
  1066. X#if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION)
  1067. X      if (!getcwd (path, PATH_MAX))
  1068. X        {
  1069. X          msg ("Couldn't get current directory.");
  1070. X          exit (EX_SYSTEM);
  1071. X        }
  1072. X#else
  1073. X      char *getwd ();
  1074. X
  1075. X      if (!getwd (path))
  1076. X        {
  1077. X          msg ("Couldn't get current directory: %s", path);
  1078. X          exit (EX_SYSTEM);
  1079. X        }
  1080. X#endif
  1081. X      chdir_name = new_name (path, chdir_name);
  1082. X      free (path);
  1083. X    }
  1084. X    }
  1085. X
  1086. X  if (name)
  1087. X    {
  1088. X      i = strlen (name);
  1089. X      /*NOSTRICT*/
  1090. X      p = (struct name *) malloc ((unsigned) (sizeof (struct name) + i));
  1091. X    }
  1092. X  else
  1093. X    p = (struct name *) malloc ((unsigned) (sizeof (struct name)));
  1094. X  if (!p)
  1095. X    {
  1096. X      if (name)
  1097. X    msg ("cannot allocate mem for name '%s'.", name);
  1098. X      else
  1099. X    msg ("cannot allocate mem for chdir record.");
  1100. X      exit (EX_SYSTEM);
  1101. X    }
  1102. X  p->next = (struct name *) NULL;
  1103. X  if (name)
  1104. X    {
  1105. X      p->fake = 0;
  1106. X      p->length = i;
  1107. X      strncpy (p->name, name, i);
  1108. X      p->name[i] = '\0';    /* Null term */
  1109. X    }
  1110. X  else
  1111. X    p->fake = 1;
  1112. X  p->found = 0;
  1113. X  p->regexp = 0;        /* Assume not a regular expression */
  1114. X  p->firstch = 1;        /* Assume first char is literal */
  1115. X  p->change_dir = chdir_name;
  1116. X  p->dir_contents = 0;        /* JF */
  1117. X  if (name)
  1118. X    {
  1119. X      if (index (name, '*') || index (name, '[') || index (name, '?'))
  1120. X    {
  1121. X      p->regexp = 1;    /* No, it's a regexp */
  1122. X      if (name[0] == '*' || name[0] == '[' || name[0] == '?')
  1123. X        p->firstch = 0;    /* Not even 1st char literal */
  1124. X    }
  1125. X    }
  1126. X
  1127. X  if (namelast)
  1128. X    namelast->next = p;
  1129. X  namelast = p;
  1130. X  if (!namelist)
  1131. X    namelist = p;
  1132. X}
  1133. X
  1134. X/*
  1135. X * Return nonzero if name P (from an archive) matches any name from
  1136. X * the namelist, zero if not.
  1137. X */
  1138. Xint
  1139. Xname_match (p)
  1140. X     register char *p;
  1141. X{
  1142. X  register struct name *nlp;
  1143. X  register int len;
  1144. X
  1145. Xagain:
  1146. X  if (0 == (nlp = namelist))    /* Empty namelist is easy */
  1147. X    return 1;
  1148. X  if (nlp->fake)
  1149. X    {
  1150. X      if (nlp->change_dir && chdir (nlp->change_dir))
  1151. X    msg_perror ("Can't change to directory %d", nlp->change_dir);
  1152. X      namelist = 0;
  1153. X      return 1;
  1154. X    }
  1155. X  len = strlen (p);
  1156. X  for (; nlp != 0; nlp = nlp->next)
  1157. X    {
  1158. X      /* If first chars don't match, quick skip */
  1159. X      if (nlp->firstch && nlp->name[0] != p[0])
  1160. X    continue;
  1161. X
  1162. X      /* Regular expressions (shell globbing, actually). */
  1163. X      if (nlp->regexp)
  1164. X    {
  1165. X      if (fnmatch (nlp->name, p, FNM_LEADING_DIR) == 0)
  1166. X        {
  1167. X          nlp->found = 1;    /* Remember it matched */
  1168. X          if (f_startfile)
  1169. X        {
  1170. X          free ((void *) namelist);
  1171. X          namelist = 0;
  1172. X        }
  1173. X          if (nlp->change_dir && chdir (nlp->change_dir))
  1174. X        msg_perror ("Can't change to directory %s", nlp->change_dir);
  1175. X          return 1;        /* We got a match */
  1176. X        }
  1177. X      continue;
  1178. X    }
  1179. X
  1180. X      /* Plain Old Strings */
  1181. X      if (nlp->length <= len    /* Archive len >= specified */
  1182. X      && (p[nlp->length] == '\0' || p[nlp->length] == '/')
  1183. X      /* Full match on file/dirname */
  1184. X      && strncmp (p, nlp->name, nlp->length) == 0)    /* Name compare */
  1185. X    {
  1186. X      nlp->found = 1;    /* Remember it matched */
  1187. X      if (f_startfile)
  1188. X        {
  1189. X          free ((void *) namelist);
  1190. X          namelist = 0;
  1191. X        }
  1192. X      if (nlp->change_dir && chdir (nlp->change_dir))
  1193. X        msg_perror ("Can't change to directory %s", nlp->change_dir);
  1194. X      return 1;        /* We got a match */
  1195. X    }
  1196. X    }
  1197. X
  1198. X  /*
  1199. X     * Filename from archive not found in namelist.
  1200. X     * If we have the whole namelist here, just return 0.
  1201. X     * Otherwise, read the next name in and compare it.
  1202. X     * If this was the last name, namelist->found will remain on.
  1203. X     * If not, we loop to compare the newly read name.
  1204. X     */
  1205. X  if (f_sorted_names && namelist->found)
  1206. X    {
  1207. X      name_gather ();        /* Read one more */
  1208. X      if (!namelist->found)
  1209. X    goto again;
  1210. X    }
  1211. X  return 0;
  1212. X}
  1213. X
  1214. X
  1215. X/*
  1216. X * Print the names of things in the namelist that were not matched.
  1217. X */
  1218. Xvoid
  1219. Xnames_notfound ()
  1220. X{
  1221. X  register struct name *nlp, *next;
  1222. X  register char *p;
  1223. X
  1224. X  for (nlp = namelist; nlp != 0; nlp = next)
  1225. X    {
  1226. X      next = nlp->next;
  1227. X      if (!nlp->found)
  1228. X    msg ("%s not found in archive", nlp->name);
  1229. X
  1230. X      /*
  1231. X         * We could free() the list, but the process is about
  1232. X         * to die anyway, so save some CPU time.  Amigas and
  1233. X         * other similarly broken software will need to waste
  1234. X         * the time, though.
  1235. X         */
  1236. X#ifdef amiga
  1237. X      if (!f_sorted_names)
  1238. X    free (nlp);
  1239. X#endif
  1240. X    }
  1241. X  namelist = (struct name *) NULL;
  1242. X  namelast = (struct name *) NULL;
  1243. X
  1244. X  if (f_sorted_names)
  1245. X    {
  1246. X      while (0 != (p = name_next (1)))
  1247. X    msg ("%s not found in archive", p);
  1248. X    }
  1249. X}
  1250. X
  1251. X/* These next routines were created by JF */
  1252. X
  1253. Xvoid
  1254. Xname_expand ()
  1255. X{
  1256. X  ;
  1257. X}
  1258. X
  1259. X/* This is like name_match(), except that it returns a pointer to the name
  1260. X   it matched, and doesn't set ->found  The caller will have to do that
  1261. X   if it wants to.  Oh, and if the namelist is empty, it returns 0, unlike
  1262. X   name_match(), which returns TRUE */
  1263. X
  1264. Xstruct name *
  1265. Xname_scan (p)
  1266. X     register char *p;
  1267. X{
  1268. X  register struct name *nlp;
  1269. X  register int len;
  1270. X
  1271. Xagain:
  1272. X  if (0 == (nlp = namelist))    /* Empty namelist is easy */
  1273. X    return 0;
  1274. X  len = strlen (p);
  1275. X  for (; nlp != 0; nlp = nlp->next)
  1276. X    {
  1277. X      /* If first chars don't match, quick skip */
  1278. X      if (nlp->firstch && nlp->name[0] != p[0])
  1279. X    continue;
  1280. X
  1281. X      /* Regular expressions */
  1282. X      if (nlp->regexp)
  1283. X    {
  1284. X      if (fnmatch (nlp->name, p, FNM_LEADING_DIR) == 0)
  1285. X        return nlp;        /* We got a match */
  1286. X      continue;
  1287. X    }
  1288. X
  1289. X      /* Plain Old Strings */
  1290. X      if (nlp->length <= len    /* Archive len >= specified */
  1291. X      && (p[nlp->length] == '\0' || p[nlp->length] == '/')
  1292. X      /* Full match on file/dirname */
  1293. X      && strncmp (p, nlp->name, nlp->length) == 0)    /* Name compare */
  1294. X    return nlp;        /* We got a match */
  1295. X    }
  1296. X
  1297. X  /*
  1298. X     * Filename from archive not found in namelist.
  1299. X     * If we have the whole namelist here, just return 0.
  1300. X     * Otherwise, read the next name in and compare it.
  1301. X     * If this was the last name, namelist->found will remain on.
  1302. X     * If not, we loop to compare the newly read name.
  1303. X     */
  1304. X  if (f_sorted_names && namelist->found)
  1305. X    {
  1306. X      name_gather ();        /* Read one more */
  1307. X      if (!namelist->found)
  1308. X    goto again;
  1309. X    }
  1310. X  return (struct name *) 0;
  1311. X}
  1312. X
  1313. X/* This returns a name from the namelist which doesn't have ->found set.
  1314. X   It sets ->found before returning, so successive calls will find and return
  1315. X   all the non-found names in the namelist */
  1316. X
  1317. Xstruct name *gnu_list_name;
  1318. X
  1319. Xchar *
  1320. Xname_from_list ()
  1321. X{
  1322. X  if (!gnu_list_name)
  1323. X    gnu_list_name = namelist;
  1324. X  while (gnu_list_name && gnu_list_name->found)
  1325. X    gnu_list_name = gnu_list_name->next;
  1326. X  if (gnu_list_name)
  1327. X    {
  1328. X      gnu_list_name->found++;
  1329. X      if (gnu_list_name->change_dir)
  1330. X    if (chdir (gnu_list_name->change_dir) < 0)
  1331. X      msg_perror ("can't chdir to %s", gnu_list_name->change_dir);
  1332. X      return gnu_list_name->name;
  1333. X    }
  1334. X  return (char *) 0;
  1335. X}
  1336. X
  1337. Xvoid
  1338. Xblank_name_list ()
  1339. X{
  1340. X  struct name *n;
  1341. X
  1342. X  gnu_list_name = 0;
  1343. X  for (n = namelist; n; n = n->next)
  1344. X    n->found = 0;
  1345. X}
  1346. X
  1347. Xchar *
  1348. Xnew_name (path, name)
  1349. X     char *path, *name;
  1350. X{
  1351. X  char *path_buf;
  1352. X
  1353. X  path_buf = (char *) malloc (strlen (path) + strlen (name) + 2);
  1354. X  if (path_buf == 0)
  1355. X    {
  1356. X      msg ("Can't allocate memory for name '%s/%s", path, name);
  1357. X      exit (EX_SYSTEM);
  1358. X    }
  1359. X  (void) sprintf (path_buf, "%s/%s", path, name);
  1360. X  return path_buf;
  1361. X}
  1362. X
  1363. X/* returns non-zero if the luser typed 'y' or 'Y', zero otherwise. */
  1364. X
  1365. Xint
  1366. Xconfirm (action, file)
  1367. X     char *action, *file;
  1368. X{
  1369. X  int c, nl;
  1370. X  static FILE *confirm_file = 0;
  1371. X  extern FILE *msg_file;
  1372. X  extern char TTY_NAME[];
  1373. X
  1374. X  fprintf (msg_file, "%s %s?", action, file);
  1375. X  fflush (msg_file);
  1376. X  if (!confirm_file)
  1377. X    {
  1378. X      confirm_file = (archive == 0) ? fopen (TTY_NAME, "r") : stdin;
  1379. X      if (!confirm_file)
  1380. X    {
  1381. X      msg ("Can't read confirmation from user");
  1382. X      exit (EX_SYSTEM);
  1383. X    }
  1384. X    }
  1385. X  c = getc (confirm_file);
  1386. X  for (nl = c; nl != '\n' && nl != EOF; nl = getc (confirm_file))
  1387. X    ;
  1388. X  return (c == 'y' || c == 'Y');
  1389. X}
  1390. X
  1391. Xchar *x_buffer = 0;
  1392. Xint size_x_buffer;
  1393. Xint free_x_buffer;
  1394. X
  1395. Xchar **exclude = 0;
  1396. Xint size_exclude = 0;
  1397. Xint free_exclude = 0;
  1398. X
  1399. Xchar **re_exclude = 0;
  1400. Xint size_re_exclude = 0;
  1401. Xint free_re_exclude = 0;
  1402. X
  1403. Xvoid
  1404. Xadd_exclude (name)
  1405. X     char *name;
  1406. X{
  1407. X  /*    char *rname;*/
  1408. X  /*    char **tmp_ptr;*/
  1409. X  int size_buf;
  1410. X
  1411. X  un_quote_string (name);
  1412. X  size_buf = strlen (name);
  1413. X
  1414. X  if (x_buffer == 0)
  1415. X    {
  1416. X      x_buffer = (char *) ck_malloc (size_buf + 1024);
  1417. X      free_x_buffer = 1024;
  1418. X    }
  1419. X  else if (free_x_buffer <= size_buf)
  1420. X    {
  1421. X      char *old_x_buffer;
  1422. X      char **tmp_ptr;
  1423. X
  1424. X      old_x_buffer = x_buffer;
  1425. X      x_buffer = (char *) ck_realloc (x_buffer, size_x_buffer + 1024);
  1426. X      free_x_buffer = 1024;
  1427. X      for (tmp_ptr = exclude; tmp_ptr < exclude + size_exclude; tmp_ptr++)
  1428. X    *tmp_ptr = x_buffer + ((*tmp_ptr) - old_x_buffer);
  1429. X      for (tmp_ptr = re_exclude; tmp_ptr < re_exclude + size_re_exclude; tmp_ptr++)
  1430. X    *tmp_ptr = x_buffer + ((*tmp_ptr) - old_x_buffer);
  1431. X    }
  1432. X
  1433. X  if (is_regex (name))
  1434. X    {
  1435. X      if (free_re_exclude == 0)
  1436. X    {
  1437. X      re_exclude = (char **) (re_exclude ? ck_realloc (re_exclude, (size_re_exclude + 32) * sizeof (char *)): ck_malloc (sizeof (char *) * 32));
  1438. X      free_re_exclude += 32;
  1439. X    }
  1440. X      re_exclude[size_re_exclude] = x_buffer + size_x_buffer;
  1441. X      size_re_exclude++;
  1442. X      free_re_exclude--;
  1443. X    }
  1444. X  else
  1445. X    {
  1446. X      if (free_exclude == 0)
  1447. X    {
  1448. X      exclude = (char **) (exclude ? ck_realloc (exclude, (size_exclude + 32) * sizeof (char *)): ck_malloc (sizeof (char *) * 32));
  1449. X      free_exclude += 32;
  1450. X    }
  1451. X      exclude[size_exclude] = x_buffer + size_x_buffer;
  1452. X      size_exclude++;
  1453. X      free_exclude--;
  1454. X    }
  1455. X  strcpy (x_buffer + size_x_buffer, name);
  1456. X  size_x_buffer += size_buf + 1;
  1457. X  free_x_buffer -= size_buf + 1;
  1458. X}
  1459. X
  1460. Xvoid
  1461. Xadd_exclude_file (file)
  1462. X     char *file;
  1463. X{
  1464. X  FILE *fp;
  1465. X  char buf[1024];
  1466. X
  1467. X  if (strcmp (file, "-"))
  1468. X    fp = fopen (file, "r");
  1469. X  else
  1470. X    /* Let's hope the person knows what they're doing. */
  1471. X    /* Using -X - -T - -f - will get you *REALLY* strange
  1472. X           results. . . */
  1473. X    fp = stdin;
  1474. X
  1475. X  if (!fp)
  1476. X    {
  1477. X      msg_perror ("can't open %s", file);
  1478. X      exit (2);
  1479. X    }
  1480. X  while (fgets (buf, 1024, fp))
  1481. X    {
  1482. X      /*        int size_buf;*/
  1483. X      char *end_str;
  1484. X
  1485. X      end_str = rindex (buf, '\n');
  1486. X      if (end_str)
  1487. X    *end_str = '\0';
  1488. X      add_exclude (buf);
  1489. X
  1490. X    }
  1491. X  fclose (fp);
  1492. X}
  1493. X
  1494. Xint
  1495. Xis_regex (str)
  1496. X     char *str;
  1497. X{
  1498. X  return index (str, '*') || index (str, '[') || index (str, '?');
  1499. X}
  1500. X
  1501. X/* Returns non-zero if the file 'name' should not be added/extracted */
  1502. Xint
  1503. Xcheck_exclude (name)
  1504. X     char *name;
  1505. X{
  1506. X  int n;
  1507. X  char *str;
  1508. X  extern char *strstr ();
  1509. X
  1510. X  for (n = 0; n < size_re_exclude; n++)
  1511. X    {
  1512. X      if (fnmatch (re_exclude[n], name, FNM_LEADING_DIR) == 0)
  1513. X    return 1;
  1514. X    }
  1515. X  for (n = 0; n < size_exclude; n++)
  1516. X    {
  1517. X      /* Accept the output from strstr only if it is the last
  1518. X           part of the string.  There is certainly a faster way to
  1519. X           do this. . . */
  1520. X      if ((str = strstr (name, exclude[n]))
  1521. X      && (str == name || str[-1] == '/')
  1522. X      && str[strlen (exclude[n])] == '\0')
  1523. X    return 1;
  1524. X    }
  1525. X  return 0;
  1526. X}
  1527. END_OF_FILE
  1528. if test 36191 -ne `wc -c <'tar.c'`; then
  1529.     echo shar: \"'tar.c'\" unpacked with wrong size!
  1530. fi
  1531. # end of 'tar.c'
  1532. fi
  1533. if test -f 'create.c' -a "${1}" != "-c" ; then 
  1534.   echo shar: Will not clobber existing file \"'create.c'\"
  1535. else
  1536. echo shar: Extracting \"'create.c'\" \(33888 characters\)
  1537. sed "s/^X//" >'create.c' <<'END_OF_FILE'
  1538. X/* Create a tar archive.
  1539. X   Copyright (C) 1985, 1992, 1993 Free Software Foundation
  1540. X
  1541. XThis file is part of GNU Tar.
  1542. X
  1543. XGNU Tar is free software; you can redistribute it and/or modify
  1544. Xit under the terms of the GNU General Public License as published by
  1545. Xthe Free Software Foundation; either version 2, or (at your option)
  1546. Xany later version.
  1547. X
  1548. XGNU Tar is distributed in the hope that it will be useful,
  1549. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  1550. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1551. XGNU General Public License for more details.
  1552. X
  1553. XYou should have received a copy of the GNU General Public License
  1554. Xalong with GNU Tar; see the file COPYING.  If not, write to
  1555. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  1556. X
  1557. X/*
  1558. X * Create a tar archive.
  1559. X *
  1560. X * Written 25 Aug 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  1561. X */
  1562. X
  1563. X#ifdef _AIX
  1564. X #pragma alloca
  1565. X#endif
  1566. X#include <sys/types.h>
  1567. X#include <stdio.h>
  1568. X#include <errno.h>
  1569. X#ifndef STDC_HEADERS
  1570. Xextern int errno;
  1571. X#endif
  1572. X
  1573. X#ifdef BSD42
  1574. X#include <sys/file.h>
  1575. X#else
  1576. X#ifndef V7
  1577. X#include <fcntl.h>
  1578. X#endif
  1579. X#endif
  1580. X
  1581. X#include "tar.h"
  1582. X#include "port.h"
  1583. X
  1584. X#ifndef    __MSDOS__
  1585. X#include <pwd.h>
  1586. X#include <grp.h>
  1587. X#endif
  1588. X
  1589. X#if defined (_POSIX_VERSION)
  1590. X#include <utime.h>
  1591. X#else
  1592. Xstruct utimbuf
  1593. X{
  1594. X  long actime;
  1595. X  long modtime;
  1596. X};
  1597. X
  1598. X#endif
  1599. X
  1600. Xextern struct stat hstat;    /* Stat struct corresponding */
  1601. X
  1602. X#ifndef __MSDOS__
  1603. Xextern dev_t ar_dev;
  1604. Xextern ino_t ar_ino;
  1605. X#endif
  1606. X
  1607. X/* JF */
  1608. Xextern struct name *gnu_list_name;
  1609. X
  1610. X/*
  1611. X * If there are no symbolic links, there is no lstat().  Use stat().
  1612. X */
  1613. X#ifndef S_ISLNK
  1614. X#define lstat stat
  1615. X#endif
  1616. X
  1617. Xextern void print_header ();
  1618. X
  1619. Xunion record *start_header ();
  1620. Xvoid blank_name_list ();
  1621. Xint check_exclude ();
  1622. XPTR ck_malloc ();
  1623. XPTR ck_realloc ();
  1624. Xvoid clear_buffer ();
  1625. Xvoid close_archive ();
  1626. Xvoid collect_and_sort_names ();
  1627. Xint confirm ();
  1628. Xint deal_with_sparse ();
  1629. Xvoid find_new_file_size ();
  1630. Xvoid finish_header ();
  1631. Xint finish_sparse_file ();
  1632. Xvoid finduname ();
  1633. Xvoid findgname ();
  1634. Xint is_dot_or_dotdot ();
  1635. Xvoid open_archive ();
  1636. Xchar *name_next ();
  1637. Xvoid name_close ();
  1638. Xvoid to_oct ();
  1639. Xvoid dump_file ();
  1640. Xvoid write_dir_file ();
  1641. Xvoid write_eot ();
  1642. Xvoid write_long ();
  1643. Xint zero_record ();
  1644. X
  1645. X/* This code moved from tar.h since create.c is the only file that cares
  1646. X   about 'struct link's.  This means that other files might not have to
  1647. X   include sys/types.h any more. */
  1648. X
  1649. Xstruct link
  1650. X  {
  1651. X    struct link *next;
  1652. X    dev_t dev;
  1653. X    ino_t ino;
  1654. X    short linkcount;
  1655. X    char name[1];
  1656. X  };
  1657. X
  1658. Xstruct link *linklist;        /* Points to first link in list */
  1659. X
  1660. Xstatic nolinks;            /* Gets set if we run out of RAM */
  1661. X
  1662. X/*
  1663. X * "Scratch" space to store the information about a sparse file before
  1664. X * writing the info into the header or extended header
  1665. X */
  1666. X/* struct sp_array     *sparsearray;*/
  1667. X
  1668. X/* number of elts storable in the sparsearray */
  1669. X/*int     sparse_array_size = 10;*/
  1670. X
  1671. Xvoid
  1672. Xcreate_archive ()
  1673. X{
  1674. X  register char *p;
  1675. X  char *name_from_list ();
  1676. X
  1677. X  open_archive (0);        /* Open for writing */
  1678. X
  1679. X  if (f_gnudump)
  1680. X    {
  1681. X      char *buf = ck_malloc (PATH_MAX);
  1682. X      char *q, *bufp;
  1683. X
  1684. X      collect_and_sort_names ();
  1685. X
  1686. X      while (p = name_from_list ())
  1687. X    dump_file (p, -1, 1);
  1688. X      /* if(!f_dironly) { */
  1689. X      blank_name_list ();
  1690. X      while (p = name_from_list ())
  1691. X    {
  1692. X      strcpy (buf, p);
  1693. X      if (p[strlen (p) - 1] != '/')
  1694. X        strcat (buf, "/");
  1695. X      bufp = buf + strlen (buf);
  1696. X      for (q = gnu_list_name->dir_contents; q && *q; q += strlen (q) + 1)
  1697. X        {
  1698. X          if (*q == 'Y')
  1699. X        {
  1700. X          strcpy (bufp, q + 1);
  1701. X          dump_file (buf, -1, 1);
  1702. X        }
  1703. X        }
  1704. X    }
  1705. X      /* } */
  1706. X      free (buf);
  1707. X    }
  1708. X  else
  1709. X    {
  1710. X      while (p = name_next (1))
  1711. X    dump_file (p, -1, 1);
  1712. X    }
  1713. X
  1714. X  write_eot ();
  1715. X  close_archive ();
  1716. X  if (f_gnudump)
  1717. X    write_dir_file ();
  1718. X  name_close ();
  1719. X}
  1720. X
  1721. X/*
  1722. X * Dump a single file.  If it's a directory, recurse.
  1723. X * Result is 1 for success, 0 for failure.
  1724. X * Sets global "hstat" to stat() output for this file.
  1725. X */
  1726. Xvoid
  1727. Xdump_file (p, curdev, toplevel)
  1728. X     char *p;            /* File name to dump */
  1729. X     int curdev;        /* Device our parent dir was on */
  1730. X     int toplevel;        /* Whether we are a toplevel call */
  1731. X{
  1732. X  union record *header;
  1733. X  char type;
  1734. X  extern char *save_name;    /* JF for multi-volume support */
  1735. X  extern long save_totsize;
  1736. X  extern long save_sizeleft;
  1737. X  union record *exhdr;
  1738. X  char save_linkflag;
  1739. X  extern time_t new_time;
  1740. X  int critical_error = 0;
  1741. X  struct utimbuf restore_times;
  1742. X  /*    int sparse_ind = 0;*/
  1743. X
  1744. X
  1745. X  if (f_confirm && !confirm ("add", p))
  1746. X    return;
  1747. X
  1748. X  /*
  1749. X     * Use stat if following (rather than dumping) 4.2BSD's
  1750. X     * symbolic links.  Otherwise, use lstat (which, on non-4.2
  1751. X     * systems, is #define'd to stat anyway.
  1752. X     */
  1753. X#ifdef STX_HIDDEN        /* AIX */
  1754. X  if (0 != f_follow_links ?
  1755. X      statx (p, &hstat, STATSIZE, STX_HIDDEN) :
  1756. X      statx (p, &hstat, STATSIZE, STX_HIDDEN | STX_LINK))
  1757. X#else
  1758. X  if (0 != f_follow_links ? stat (p, &hstat) : lstat (p, &hstat))
  1759. X#endif
  1760. X    {
  1761. X    badperror:
  1762. X      msg_perror ("can't add file %s", p);
  1763. X    badfile:
  1764. X      if (!f_ignore_failed_read || critical_error)
  1765. X    errors++;
  1766. X      return;
  1767. X    }
  1768. X
  1769. X  restore_times.actime = hstat.st_atime;
  1770. X  restore_times.modtime = hstat.st_mtime;
  1771. X
  1772. X#ifdef S_ISHIDDEN
  1773. X  if (S_ISHIDDEN (hstat.st_mode))
  1774. X    {
  1775. X      char *new = (char *) alloca (strlen (p) + 2);
  1776. X      if (new)
  1777. X    {
  1778. X      strcpy (new, p);
  1779. X      strcat (new, "@");
  1780. X      p = new;
  1781. X    }
  1782. X    }
  1783. X#endif
  1784. X
  1785. X  /* See if we only want new files, and check if this one is too old to
  1786. X       put in the archive. */
  1787. X  if (f_new_files
  1788. X      && !f_gnudump
  1789. X      && new_time > hstat.st_mtime
  1790. X      && !S_ISDIR (hstat.st_mode)
  1791. X      && (f_new_files > 1 || new_time > hstat.st_ctime))
  1792. X    {
  1793. X      if (curdev == -1)
  1794. X    {
  1795. X      msg ("%s: is unchanged; not dumped", p);
  1796. X    }
  1797. X      return;
  1798. X    }
  1799. X
  1800. X#ifndef __MSDOS__
  1801. X  /* See if we are trying to dump the archive */
  1802. X  if (ar_dev && hstat.st_dev == ar_dev && hstat.st_ino == ar_ino)
  1803. X    {
  1804. X      msg ("%s is the archive; not dumped", p);
  1805. X      return;
  1806. X    }
  1807. X#endif
  1808. X  /*
  1809. X     * Check for multiple links.
  1810. X     *
  1811. X     * We maintain a list of all such files that we've written so
  1812. X     * far.  Any time we see another, we check the list and
  1813. X     * avoid dumping the data again if we've done it once already.
  1814. X     */
  1815. X  if (hstat.st_nlink > 1
  1816. X      && (S_ISREG (hstat.st_mode)
  1817. X#ifdef S_ISCTG
  1818. X      || S_ISCTG (hstat.st_mode)
  1819. X#endif
  1820. X#ifdef S_ISCHR
  1821. X      || S_ISCHR (hstat.st_mode)
  1822. X#endif
  1823. X#ifdef S_ISBLK
  1824. X      || S_ISBLK (hstat.st_mode)
  1825. X#endif
  1826. X#ifdef S_ISFIFO
  1827. X      || S_ISFIFO (hstat.st_mode)
  1828. X#endif
  1829. X      ))
  1830. X    {
  1831. X      register struct link *lp;
  1832. X
  1833. X      /* First quick and dirty.  Hashing, etc later FIXME */
  1834. X      for (lp = linklist; lp; lp = lp->next)
  1835. X    {
  1836. X      if (lp->ino == hstat.st_ino &&
  1837. X          lp->dev == hstat.st_dev)
  1838. X        {
  1839. X          char *link_name = lp->name;
  1840. X
  1841. X          /* We found a link. */
  1842. X          while (!f_absolute_paths && *link_name == '/')
  1843. X        {
  1844. X          static int link_warn = 0;
  1845. X
  1846. X          if (!link_warn)
  1847. X            {
  1848. X              msg ("Removing leading / from absolute links");
  1849. X              link_warn++;
  1850. X            }
  1851. X          link_name++;
  1852. X        }
  1853. X          if (link_name - lp->name >= NAMSIZ)
  1854. X        write_long (link_name, LF_LONGLINK);
  1855. X          current_link_name = link_name;
  1856. X
  1857. X          hstat.st_size = 0;
  1858. X          header = start_header (p, &hstat);
  1859. X          if (header == NULL)
  1860. X        {
  1861. X          critical_error = 1;
  1862. X          goto badfile;
  1863. X        }
  1864. X          strncpy (header->header.arch_linkname,
  1865. X               link_name, NAMSIZ);
  1866. X
  1867. X          /* Force null truncated */
  1868. X          header->header.arch_linkname[NAMSIZ - 1] = 0;
  1869. X
  1870. X          header->header.linkflag = LF_LINK;
  1871. X          finish_header (header);
  1872. X          /* FIXME: Maybe remove from list after all links found? */
  1873. X          if (f_remove_files)
  1874. X        {
  1875. X          if (unlink (p) == -1)
  1876. X            msg_perror ("cannot remove %s", p);
  1877. X        }
  1878. X          return;        /* We dumped it */
  1879. X        }
  1880. X    }
  1881. X
  1882. X      /* Not found.  Add it to the list of possible links. */
  1883. X      lp = (struct link *) ck_malloc ((unsigned) (sizeof (struct link) + strlen (p)));
  1884. X      if (!lp)
  1885. X    {
  1886. X      if (!nolinks)
  1887. X        {
  1888. X          msg (
  1889. X          "no memory for links, they will be dumped as separate files");
  1890. X          nolinks++;
  1891. X        }
  1892. X    }
  1893. X      lp->ino = hstat.st_ino;
  1894. X      lp->dev = hstat.st_dev;
  1895. X      strcpy (lp->name, p);
  1896. X      lp->next = linklist;
  1897. X      linklist = lp;
  1898. X    }
  1899. X
  1900. X  /*
  1901. X     * This is not a link to a previously dumped file, so dump it.
  1902. X     */
  1903. X  if (S_ISREG (hstat.st_mode)
  1904. X#ifdef S_ISCTG
  1905. X      || S_ISCTG (hstat.st_mode)
  1906. X#endif
  1907. X    )
  1908. X    {
  1909. X      int f;            /* File descriptor */
  1910. X      long bufsize, count;
  1911. X      long sizeleft;
  1912. X      register union record *start;
  1913. X      int header_moved;
  1914. X      char isextended = 0;
  1915. X      int upperbound;
  1916. X      /*        int    end_nulls = 0; */
  1917. X
  1918. X      header_moved = 0;
  1919. X
  1920. X#ifdef BSD42
  1921. X      if (f_sparse_files)
  1922. X    {
  1923. X      /*
  1924. X          * JK - This is the test for sparseness: whether the
  1925. X         * "size" of the file matches the number of blocks
  1926. X         * allocated for it.  If there is a smaller number
  1927. X         * of blocks that would be necessary to accommodate
  1928. X         * a file of this size, we have a sparse file, i.e.,
  1929. X         * at least one of those records in the file is just
  1930. X         * a useless hole.
  1931. X         */
  1932. X#ifdef hpux            /* Nice of HPUX to gratuitiously change it, huh?  - mib */
  1933. X      if (hstat.st_size - (hstat.st_blocks * 1024) > 1024)
  1934. X#else
  1935. X      if (hstat.st_size - (hstat.st_blocks * RECORDSIZE) > RECORDSIZE)
  1936. X#endif
  1937. X        {
  1938. X          int filesize = hstat.st_size;
  1939. X          register int i;
  1940. X
  1941. X          header = start_header (p, &hstat);
  1942. X          if (header == NULL)
  1943. X        {
  1944. X          critical_error = 1;
  1945. X          goto badfile;
  1946. X        }
  1947. X          header->header.linkflag = LF_SPARSE;
  1948. X          header_moved++;
  1949. X
  1950. X          /*
  1951. X             * Call the routine that figures out the
  1952. X             * layout of the sparse file in question.
  1953. X             * UPPERBOUND is the index of the last
  1954. X             * element of the "sparsearray," i.e.,
  1955. X             * the number of elements it needed to
  1956. X             * describe the file.
  1957. X             */
  1958. X
  1959. X          upperbound = deal_with_sparse (p, header);
  1960. X
  1961. X          /*
  1962. X             * See if we'll need an extended header
  1963. X             * later
  1964. X             */
  1965. X          if (upperbound > SPARSE_IN_HDR - 1)
  1966. X        header->header.isextended++;
  1967. X          /*
  1968. X             * We store the "real" file size so
  1969. X             * we can show that in case someone wants
  1970. X             * to list the archive, i.e., tar tvf <file>.
  1971. X             * It might be kind of disconcerting if the
  1972. X             * shrunken file size was the one that showed
  1973. X             * up.
  1974. X             */
  1975. X          to_oct ((long) hstat.st_size, 1 + 12,
  1976. X              header->header.realsize);
  1977. X
  1978. X          /*
  1979. X             * This will be the new "size" of the
  1980. X             * file, i.e., the size of the file
  1981. X             * minus the records of holes that we're
  1982. X             * skipping over.
  1983. X             */
  1984. X
  1985. X          find_new_file_size (&filesize, upperbound);
  1986. X          hstat.st_size = filesize;
  1987. X          to_oct ((long) filesize, 1 + 12,
  1988. X              header->header.size);
  1989. X          /*                to_oct((long) end_nulls, 1+12,
  1990. X                        header->header.ending_blanks);*/
  1991. X
  1992. X          for (i = 0; i < SPARSE_IN_HDR; i++)
  1993. X        {
  1994. X          if (!sparsearray[i].numbytes)
  1995. X            break;
  1996. X          to_oct (sparsearray[i].offset, 1 + 12,
  1997. X              header->header.sp[i].offset);
  1998. X          to_oct (sparsearray[i].numbytes, 1 + 12,
  1999. X              header->header.sp[i].numbytes);
  2000. X        }
  2001. X
  2002. X        }
  2003. X    }
  2004. X#else
  2005. X      upperbound = SPARSE_IN_HDR - 1;
  2006. X#endif
  2007. X
  2008. X      sizeleft = hstat.st_size;
  2009. X      /* Don't bother opening empty, world readable files. */
  2010. X      if (sizeleft > 0 || 0444 != (0444 & hstat.st_mode))
  2011. X    {
  2012. X      f = open (p, O_RDONLY | O_BINARY);
  2013. X      if (f < 0)
  2014. X        goto badperror;
  2015. X    }
  2016. X      else
  2017. X    {
  2018. X      f = -1;
  2019. X    }
  2020. X
  2021. X      /* If the file is sparse, we've already taken care of this */
  2022. X      if (!header_moved)
  2023. X    {
  2024. X      header = start_header (p, &hstat);
  2025. X      if (header == NULL)
  2026. X        {
  2027. X          if (f >= 0)
  2028. X        (void) close (f);
  2029. X          critical_error = 1;
  2030. X          goto badfile;
  2031. X        }
  2032. X    }
  2033. X#ifdef S_ISCTG
  2034. X      /* Mark contiguous files, if we support them */
  2035. X      if (f_standard && S_ISCTG (hstat.st_mode))
  2036. X    {
  2037. X      header->header.linkflag = LF_CONTIG;
  2038. X    }
  2039. X#endif
  2040. X      isextended = header->header.isextended;
  2041. X      save_linkflag = header->header.linkflag;
  2042. X      finish_header (header);
  2043. X      if (isextended)
  2044. X    {
  2045. X      /*            int     sum = 0;*/
  2046. X      register int i;
  2047. X      /*            register union record *exhdr;*/
  2048. X      /*            int     arraybound = SPARSE_EXT_HDR;*/
  2049. X      /* static */ int index_offset = SPARSE_IN_HDR;
  2050. X
  2051. X    extend:exhdr = findrec ();
  2052. X
  2053. X      if (exhdr == NULL)
  2054. X        {
  2055. X          critical_error = 1;
  2056. X          goto badfile;
  2057. X        }
  2058. X      bzero (exhdr->charptr, RECORDSIZE);
  2059. X      for (i = 0; i < SPARSE_EXT_HDR; i++)
  2060. X        {
  2061. X          if (i + index_offset > upperbound)
  2062. X        break;
  2063. X          to_oct ((long) sparsearray[i + index_offset].numbytes,
  2064. X              1 + 12,
  2065. X              exhdr->ext_hdr.sp[i].numbytes);
  2066. X          to_oct ((long) sparsearray[i + index_offset].offset,
  2067. X              1 + 12,
  2068. X              exhdr->ext_hdr.sp[i].offset);
  2069. X        }
  2070. X      userec (exhdr);
  2071. X      /*            sum += i;
  2072. X            if (sum < upperbound)
  2073. X                goto extend;*/
  2074. X      if (index_offset + i <= upperbound)
  2075. X        {
  2076. X          index_offset += i;
  2077. X          exhdr->ext_hdr.isextended++;
  2078. X          goto extend;
  2079. X        }
  2080. X
  2081. X    }
  2082. X      if (save_linkflag == LF_SPARSE)
  2083. X    {
  2084. X      if (finish_sparse_file (f, &sizeleft, hstat.st_size, p))
  2085. X        goto padit;
  2086. X    }
  2087. X      else
  2088. X    while (sizeleft > 0)
  2089. X      {
  2090. X
  2091. X        if (f_multivol)
  2092. X          {
  2093. X        save_name = p;
  2094. X        save_sizeleft = sizeleft;
  2095. X        save_totsize = hstat.st_size;
  2096. X          }
  2097. X        start = findrec ();
  2098. X
  2099. X        bufsize = endofrecs ()->charptr - start->charptr;
  2100. X
  2101. X        if (sizeleft < bufsize)
  2102. X          {
  2103. X        /* Last read -- zero out area beyond */
  2104. X        bufsize = (int) sizeleft;
  2105. X        count = bufsize % RECORDSIZE;
  2106. X        if (count)
  2107. X          bzero (start->charptr + sizeleft,
  2108. X             (int) (RECORDSIZE - count));
  2109. X          }
  2110. X        count = read (f, start->charptr, bufsize);
  2111. X        if (count < 0)
  2112. X          {
  2113. X        msg_perror ("read error at byte %ld, reading\
  2114. X %d bytes, in file %s", hstat.st_size - sizeleft, bufsize, p);
  2115. X        goto padit;
  2116. X          }
  2117. X        sizeleft -= count;
  2118. X
  2119. X        /* This is nonportable (the type of userec's arg). */
  2120. X        userec (start + (count - 1) / RECORDSIZE);
  2121. X
  2122. X        if (count == bufsize)
  2123. X          continue;
  2124. X        msg ("file %s shrunk by %d bytes, padding with zeros.", p, sizeleft);
  2125. X        goto padit;        /* Short read */
  2126. X      }
  2127. X
  2128. X      if (f_multivol)
  2129. X    save_name = 0;
  2130. X
  2131. X      if (f >= 0)
  2132. X    (void) close (f);
  2133. X
  2134. X      if (f_remove_files)
  2135. X    {
  2136. X      if (unlink (p) == -1)
  2137. X        msg_perror ("cannot remove %s", p);
  2138. X    }
  2139. X      if (f_atime_preserve)
  2140. X    utime (p, &restore_times);
  2141. X      return;
  2142. X
  2143. X      /*
  2144. X         * File shrunk or gave error, pad out tape to match
  2145. X         * the size we specified in the header.
  2146. X         */
  2147. X    padit:
  2148. X      while (sizeleft > 0)
  2149. X    {
  2150. X      save_sizeleft = sizeleft;
  2151. X      start = findrec ();
  2152. X      bzero (start->charptr, RECORDSIZE);
  2153. X      userec (start);
  2154. X      sizeleft -= RECORDSIZE;
  2155. X    }
  2156. X      if (f_multivol)
  2157. X    save_name = 0;
  2158. X      if (f >= 0)
  2159. X    (void) close (f);
  2160. X      if (f_atime_preserve)
  2161. X    utime (p, &restore_times);
  2162. X      return;
  2163. X    }
  2164. X
  2165. X#ifdef S_ISLNK
  2166. X  else if (S_ISLNK (hstat.st_mode))
  2167. X    {
  2168. X      int size;
  2169. X      char *buf = alloca (PATH_MAX + 1);
  2170. X
  2171. X      size = readlink (p, buf, PATH_MAX + 1);
  2172. X      if (size < 0)
  2173. X    goto badperror;
  2174. X      buf[size] = '\0';
  2175. X      if (size >= NAMSIZ)
  2176. X    write_long (buf, LF_LONGLINK);
  2177. X      current_link_name = buf;
  2178. X
  2179. X      hstat.st_size = 0;    /* Force 0 size on symlink */
  2180. X      header = start_header (p, &hstat);
  2181. X      if (header == NULL)
  2182. X    {
  2183. X      critical_error = 1;
  2184. X      goto badfile;
  2185. X    }
  2186. X      strncpy (header->header.arch_linkname, buf, NAMSIZ);
  2187. X      header->header.arch_linkname[NAMSIZ - 1] = '\0';
  2188. X      header->header.linkflag = LF_SYMLINK;
  2189. X      finish_header (header);    /* Nothing more to do to it */
  2190. X      if (f_remove_files)
  2191. X    {
  2192. X      if (unlink (p) == -1)
  2193. X        msg_perror ("cannot remove %s", p);
  2194. X    }
  2195. X      return;
  2196. X    }
  2197. X#endif
  2198. X
  2199. X  else if (S_ISDIR (hstat.st_mode))
  2200. X    {
  2201. X      register DIR *dirp;
  2202. X      register struct dirent *d;
  2203. X      char *namebuf;
  2204. X      int buflen;
  2205. X      register int len;
  2206. X      int our_device = hstat.st_dev;
  2207. X
  2208. X      /* Build new prototype name */
  2209. X      len = strlen (p);
  2210. X      buflen = len + NAMSIZ;
  2211. X      namebuf = ck_malloc (buflen + 1);
  2212. X      strncpy (namebuf, p, buflen);
  2213. X      while (len >= 1 && '/' == namebuf[len - 1])
  2214. X    len--;            /* Delete trailing slashes */
  2215. X      namebuf[len++] = '/';    /* Now add exactly one back */
  2216. X      namebuf[len] = '\0';    /* Make sure null-terminated */
  2217. X
  2218. X      /*
  2219. X         * Output directory header record with permissions
  2220. X         * FIXME, do this AFTER files, to avoid R/O dir problems?
  2221. X         * If old archive format, don't write record at all.
  2222. X         */
  2223. X      if (!f_oldarch)
  2224. X    {
  2225. X      hstat.st_size = 0;    /* Force 0 size on dir */
  2226. X      /*
  2227. X             * If people could really read standard archives,
  2228. X             * this should be:        (FIXME)
  2229. X            header = start_header(f_standard? p: namebuf, &hstat);
  2230. X             * but since they'd interpret LF_DIR records as
  2231. X             * regular files, we'd better put the / on the name.
  2232. X             */
  2233. X      header = start_header (namebuf, &hstat);
  2234. X      if (header == NULL)
  2235. X        {
  2236. X          critical_error = 1;
  2237. X          goto badfile;    /* eg name too long */
  2238. X        }
  2239. X
  2240. X      if (f_gnudump)
  2241. X        header->header.linkflag = LF_DUMPDIR;
  2242. X      else if (f_standard)
  2243. X        header->header.linkflag = LF_DIR;
  2244. X
  2245. X      /* If we're gnudumping, we aren't done yet so don't close it. */
  2246. X      if (!f_gnudump)
  2247. X        finish_header (header);    /* Done with directory header */
  2248. X    }
  2249. X
  2250. X      if (f_gnudump)
  2251. X    {
  2252. X      int sizeleft;
  2253. X      int totsize;
  2254. X      int bufsize;
  2255. X      union record *start;
  2256. X      int count;
  2257. X      char *buf, *p_buf;
  2258. X
  2259. X      buf = gnu_list_name->dir_contents;    /* FOO */
  2260. X      totsize = 0;
  2261. X      for (p_buf = buf; p_buf && *p_buf;)
  2262. X        {
  2263. X          int tmp;
  2264. X
  2265. X          tmp = strlen (p_buf) + 1;
  2266. X          totsize += tmp;
  2267. X          p_buf += tmp;
  2268. X        }
  2269. X      totsize++;
  2270. X      to_oct ((long) totsize, 1 + 12, header->header.size);
  2271. X      finish_header (header);
  2272. X      p_buf = buf;
  2273. X      sizeleft = totsize;
  2274. X      while (sizeleft > 0)
  2275. X        {
  2276. X          if (f_multivol)
  2277. X        {
  2278. X          save_name = p;
  2279. X          save_sizeleft = sizeleft;
  2280. X          save_totsize = totsize;
  2281. X        }
  2282. X          start = findrec ();
  2283. X          bufsize = endofrecs ()->charptr - start->charptr;
  2284. X          if (sizeleft < bufsize)
  2285. X        {
  2286. X          bufsize = sizeleft;
  2287. X          count = bufsize % RECORDSIZE;
  2288. X          if (count)
  2289. X            bzero (start->charptr + sizeleft, RECORDSIZE - count);
  2290. X        }
  2291. X          bcopy (p_buf, start->charptr, bufsize);
  2292. X          sizeleft -= bufsize;
  2293. X          p_buf += bufsize;
  2294. X          userec (start + (bufsize - 1) / RECORDSIZE);
  2295. X        }
  2296. X      if (f_multivol)
  2297. X        save_name = 0;
  2298. X      if (f_atime_preserve)
  2299. X        utime (p, &restore_times);
  2300. X      return;
  2301. X    }
  2302. X
  2303. X      /* Now output all the files in the directory */
  2304. X#if 0
  2305. X      if (f_dironly)
  2306. X    return;            /* Unless the cmdline said not to */
  2307. X#endif
  2308. X      /*
  2309. X         * See if we are crossing from one file system to another,
  2310. X         * and avoid doing so if the user only wants to dump one file system.
  2311. X         */
  2312. X      if (f_local_filesys && !toplevel && curdev != hstat.st_dev)
  2313. X    {
  2314. X      if (f_verbose)
  2315. X        msg ("%s: is on a different filesystem; not dumped", p);
  2316. X      return;
  2317. X    }
  2318. X
  2319. X
  2320. X      errno = 0;
  2321. X      dirp = opendir (p);
  2322. X      if (!dirp)
  2323. X    {
  2324. X      if (errno)
  2325. X        {
  2326. X          msg_perror ("can't open directory %s", p);
  2327. X        }
  2328. X      else
  2329. X        {
  2330. X          msg ("error opening directory %s",
  2331. X           p);
  2332. X        }
  2333. X      return;
  2334. X    }
  2335. X
  2336. X      /* Hack to remove "./" from the front of all the file names */
  2337. X      if (len == 2 && namebuf[0] == '.' && namebuf[1] == '/')
  2338. X    len = 0;
  2339. X
  2340. X      /* Should speed this up by cd-ing into the dir, FIXME */
  2341. X      while (NULL != (d = readdir (dirp)))
  2342. X    {
  2343. X      /* Skip . and .. */
  2344. X      if (is_dot_or_dotdot (d->d_name))
  2345. X        continue;
  2346. X
  2347. X      if (NLENGTH (d) + len >= buflen)
  2348. X        {
  2349. X          buflen = len + NLENGTH (d);
  2350. X          namebuf = ck_realloc (namebuf, buflen + 1);
  2351. X          /* namebuf[len]='\0';
  2352. X                msg("file name %s%s too long",
  2353. X                    namebuf, d->d_name);
  2354. X                continue; */
  2355. X        }
  2356. X      strcpy (namebuf + len, d->d_name);
  2357. X      if (f_exclude && check_exclude (namebuf))
  2358. X        continue;
  2359. X      dump_file (namebuf, our_device, 0);
  2360. X    }
  2361. X
  2362. X      closedir (dirp);
  2363. X      free (namebuf);
  2364. X      if (f_atime_preserve)
  2365. X    utime (p, &restore_times);
  2366. X      return;
  2367. X    }
  2368. X
  2369. X#ifdef S_ISCHR
  2370. X  else if (S_ISCHR (hstat.st_mode))
  2371. X    {
  2372. X      type = LF_CHR;
  2373. X    }
  2374. X#endif
  2375. X
  2376. X#ifdef S_ISBLK
  2377. X  else if (S_ISBLK (hstat.st_mode))
  2378. X    {
  2379. X      type = LF_BLK;
  2380. X    }
  2381. X#endif
  2382. X
  2383. X  /* Avoid screwy apollo lossage where S_IFIFO == S_IFSOCK */
  2384. X#if (_ISP__M68K == 0) && (_ISP__A88K == 0) && defined(S_ISFIFO)
  2385. X  else if (S_ISFIFO (hstat.st_mode))
  2386. X    {
  2387. X      type = LF_FIFO;
  2388. X    }
  2389. X#endif
  2390. X
  2391. X#ifdef S_ISSOCK
  2392. X  else if (S_ISSOCK (hstat.st_mode))
  2393. X    {
  2394. X      type = LF_FIFO;
  2395. X    }
  2396. X#endif
  2397. X  else
  2398. X    goto unknown;
  2399. X
  2400. X  if (!f_standard)
  2401. X    goto unknown;
  2402. X
  2403. X  hstat.st_size = 0;        /* Force 0 size */
  2404. X  header = start_header (p, &hstat);
  2405. X  if (header == NULL)
  2406. X    {
  2407. X      critical_error = 1;
  2408. X      goto badfile;        /* eg name too long */
  2409. X    }
  2410. X
  2411. X  header->header.linkflag = type;
  2412. X#if defined(S_IFBLK) || defined(S_IFCHR)
  2413. X  if (type != LF_FIFO)
  2414. X    {
  2415. X      to_oct ((long) major (hstat.st_rdev), 8,
  2416. X          header->header.devmajor);
  2417. X      to_oct ((long) minor (hstat.st_rdev), 8,
  2418. X          header->header.devminor);
  2419. X    }
  2420. X#endif
  2421. X
  2422. X  finish_header (header);
  2423. X  if (f_remove_files)
  2424. X    {
  2425. X      if (unlink (p) == -1)
  2426. X    msg_perror ("cannot remove %s", p);
  2427. X    }
  2428. X  return;
  2429. X
  2430. Xunknown:
  2431. X  msg ("%s: Unknown file type; file ignored.", p);
  2432. X}
  2433. X
  2434. Xint
  2435. Xfinish_sparse_file (fd, sizeleft, fullsize, name)
  2436. X     int fd;
  2437. X     long *sizeleft, fullsize;
  2438. X     char *name;
  2439. X{
  2440. X  union record *start;
  2441. X  char tempbuf[RECORDSIZE];
  2442. X  int bufsize, sparse_ind = 0, count;
  2443. X  long pos;
  2444. X  long nwritten = 0;
  2445. X
  2446. X
  2447. X  while (*sizeleft > 0)
  2448. X    {
  2449. X      start = findrec ();
  2450. X      bzero (start->charptr, RECORDSIZE);
  2451. X      bufsize = sparsearray[sparse_ind].numbytes;
  2452. X      if (!bufsize)
  2453. X    {            /* we blew it, maybe */
  2454. X      msg ("Wrote %ld of %ld bytes to file %s",
  2455. X           fullsize - *sizeleft, fullsize, name);
  2456. X      break;
  2457. X    }
  2458. X      pos = lseek (fd, sparsearray[sparse_ind++].offset, 0);
  2459. X      /*
  2460. X         * If the number of bytes to be written here exceeds
  2461. X         * the size of the temporary buffer, do it in steps.
  2462. X         */
  2463. X      while (bufsize > RECORDSIZE)
  2464. X    {
  2465. X      /*            if (amt_read) {
  2466. X                count = read(fd, start->charptr+amt_read, RECORDSIZE-amt_read);
  2467. X                bufsize -= RECORDSIZE - amt_read;
  2468. X                amt_read = 0;
  2469. X                userec(start);
  2470. X                start = findrec();
  2471. X                bzero(start->charptr, RECORDSIZE);
  2472. X            }*/
  2473. X      /* store the data */
  2474. X      count = read (fd, start->charptr, RECORDSIZE);
  2475. X      if (count < 0)
  2476. X        {
  2477. X          msg_perror ("read error at byte %ld, reading %d bytes, in file %s",
  2478. X              fullsize - *sizeleft, bufsize, name);
  2479. X          return 1;
  2480. X        }
  2481. X      bufsize -= count;
  2482. X      *sizeleft -= count;
  2483. X      userec (start);
  2484. X      nwritten += RECORDSIZE;    /* XXX */
  2485. X      start = findrec ();
  2486. X      bzero (start->charptr, RECORDSIZE);
  2487. X    }
  2488. X
  2489. X
  2490. X      clear_buffer (tempbuf);
  2491. X      count = read (fd, tempbuf, bufsize);
  2492. X      bcopy (tempbuf, start->charptr, RECORDSIZE);
  2493. X      if (count < 0)
  2494. X    {
  2495. X      msg_perror ("read error at byte %ld, reading %d bytes, in file %s",
  2496. X              fullsize - *sizeleft, bufsize, name);
  2497. X      return 1;
  2498. X    }
  2499. X      /*        if (amt_read >= RECORDSIZE) {
  2500. X            amt_read = 0;
  2501. X            userec(start+(count-1)/RECORDSIZE);
  2502. X            if (count != bufsize) {
  2503. X                msg("file %s shrunk by %d bytes, padding with zeros.", name, sizeleft);
  2504. X                return 1;
  2505. X            }
  2506. X            start = findrec();
  2507. X        } else
  2508. X            amt_read += bufsize;*/
  2509. X      nwritten += count;    /* XXX */
  2510. X      *sizeleft -= count;
  2511. X      userec (start);
  2512. X
  2513. X    }
  2514. X  free (sparsearray);
  2515. X  /*    printf ("Amount actually written is (I hope) %d.\n", nwritten); */
  2516. X  /*    userec(start+(count-1)/RECORDSIZE);*/
  2517. X  return 0;
  2518. X
  2519. X}
  2520. X
  2521. Xvoid
  2522. Xinit_sparsearray ()
  2523. X{
  2524. X  register int i;
  2525. X
  2526. X  sp_array_size = 10;
  2527. X  /*
  2528. X     * Make room for our scratch space -- initially is 10 elts long
  2529. X     */
  2530. X  sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
  2531. X  for (i = 0; i < sp_array_size; i++)
  2532. X    {
  2533. X      sparsearray[i].offset = 0;
  2534. X      sparsearray[i].numbytes = 0;
  2535. X    }
  2536. X}
  2537. X
  2538. X
  2539. X
  2540. X/*
  2541. X * Okay, we've got a sparse file on our hands -- now, what we need to do is
  2542. X * make a pass through the file and carefully note where any data is, i.e.,
  2543. X * we want to find how far into the file each instance of data is, and how
  2544. X * many bytes are there.  We store this information in the sparsearray,
  2545. X * which will later be translated into header information.  For now, we use
  2546. X * the sparsearray as convenient storage.
  2547. X *
  2548. X * As a side note, this routine is a mess.  If I could have found a cleaner
  2549. X * way to do it, I would have.  If anyone wants to find a nicer way to do
  2550. X * this, feel free.
  2551. X */
  2552. X
  2553. X/* There is little point in trimming small amounts of null data at the */
  2554. X/* head and tail of blocks -- it's ok if we only avoid dumping blocks */
  2555. X/* of complete null data */
  2556. Xint
  2557. Xdeal_with_sparse (name, header, nulls_at_end)
  2558. X     char *name;
  2559. X     union record *header;
  2560. X     int nulls_at_end;
  2561. X{
  2562. X  long numbytes = 0;
  2563. X  long offset = 0;
  2564. X  /*    long    save_offset;*/
  2565. X  int fd;
  2566. X  /*    int    current_size = hstat.st_size;*/
  2567. X  int sparse_ind = 0, cc;
  2568. X  char buf[RECORDSIZE];
  2569. X#if 0
  2570. X  int read_last_data = 0;    /* did we just read the last record? */
  2571. X#endif
  2572. X  int amidst_data = 0;
  2573. X
  2574. X  header->header.isextended = 0;
  2575. X  /*
  2576. X     * Can't open the file -- this problem will be caught later on,
  2577. X     * so just return.
  2578. X     */
  2579. X  if ((fd = open (name, O_RDONLY)) < 0)
  2580. X    return 0;
  2581. X
  2582. X  init_sparsearray ();
  2583. X  clear_buffer (buf);
  2584. X
  2585. X  while ((cc = read (fd, buf, sizeof buf)) != 0)
  2586. X    {
  2587. X
  2588. X      if (sparse_ind > sp_array_size - 1)
  2589. X    {
  2590. X
  2591. X      /*
  2592. X         * realloc the scratch area, since we've run out of room --
  2593. X         */
  2594. X      sparsearray = (struct sp_array *)
  2595. X        ck_realloc (sparsearray,
  2596. X             2 * sp_array_size * (sizeof (struct sp_array)));
  2597. X      sp_array_size *= 2;
  2598. X    }
  2599. X      if (cc == sizeof buf)
  2600. X    {
  2601. X      if (zero_record (buf))
  2602. X        {
  2603. X          if (amidst_data)
  2604. X        {
  2605. X          sparsearray[sparse_ind++].numbytes
  2606. X            = numbytes;
  2607. X          amidst_data = 0;
  2608. X        }
  2609. X        }
  2610. X      else
  2611. X        {            /* !zero_record(buf) */
  2612. X          if (amidst_data)
  2613. X        numbytes += cc;
  2614. X          else
  2615. X        {
  2616. X          amidst_data = 1;
  2617. X          numbytes = cc;
  2618. X          sparsearray[sparse_ind].offset
  2619. X            = offset;
  2620. X        }
  2621. X        }
  2622. X    }
  2623. X      else if (cc < sizeof buf)
  2624. X    {
  2625. X      /* This has to be the last bit of the file, so this */
  2626. X      /* is somewhat shorter than the above. */
  2627. X      if (!zero_record (buf))
  2628. X        {
  2629. X          if (!amidst_data)
  2630. X        {
  2631. X          amidst_data = 1;
  2632. X          numbytes = cc;
  2633. X          sparsearray[sparse_ind].offset
  2634. X            = offset;
  2635. X        }
  2636. X          else
  2637. X        numbytes += cc;
  2638. X        }
  2639. X    }
  2640. X      offset += cc;
  2641. X      clear_buffer (buf);
  2642. X    }
  2643. X  if (amidst_data)
  2644. X    sparsearray[sparse_ind++].numbytes = numbytes;
  2645. X  else
  2646. X    {
  2647. X      sparsearray[sparse_ind].offset = offset-1;
  2648. X      sparsearray[sparse_ind++].numbytes = 1;
  2649. X    }
  2650. X  close (fd);
  2651. X
  2652. X  return sparse_ind - 1;
  2653. X}
  2654. X
  2655. X/*
  2656. X * Just zeroes out the buffer so we don't confuse ourselves with leftover
  2657. X * data.
  2658. X */
  2659. Xvoid
  2660. Xclear_buffer (buf)
  2661. X     char *buf;
  2662. X{
  2663. X  register int i;
  2664. X
  2665. X  for (i = 0; i < RECORDSIZE; i++)
  2666. X    buf[i] = '\0';
  2667. X}
  2668. X
  2669. X#if 0                /* I'm leaving this as a monument to Joy Kendall, who wrote it -mib */
  2670. X/*
  2671. X * JK -
  2672. X * This routine takes a character array, and tells where within that array
  2673. X * the data can be found.  It skips over any zeros, and sets the first
  2674. X * non-zero point in the array to be the "start", and continues until it
  2675. X * finds non-data again, which is marked as the "end."  This routine is
  2676. X * mainly for 1) seeing how far into a file we must lseek to data, given
  2677. X * that we have a sparse file, and 2) determining the "real size" of the
  2678. X * file, i.e., the number of bytes in the sparse file that are data, as
  2679. X * opposed to the zeros we are trying to skip.
  2680. X */
  2681. Xwhere_is_data (from, to, buffer)
  2682. X     int *from, *to;
  2683. X     char *buffer;
  2684. X{
  2685. X  register int i = 0;
  2686. X  register int save_to = *to;
  2687. X  int amidst_data = 0;
  2688. X
  2689. X
  2690. X  while (!buffer[i])
  2691. X    i++;
  2692. X  *from = i;
  2693. X
  2694. X  if (*from < 16)        /* don't bother */
  2695. X    *from = 0;
  2696. X  /* keep going to make sure there isn't more real
  2697. X       data in this record */
  2698. X  while (i < RECORDSIZE)
  2699. X    {
  2700. X      if (!buffer[i])
  2701. X    {
  2702. X      if (amidst_data)
  2703. X        {
  2704. X          save_to = i;
  2705. X          amidst_data = 0;
  2706. X        }
  2707. X      i++;
  2708. X    }
  2709. X      else if (buffer[i])
  2710. X    {
  2711. X      if (!amidst_data)
  2712. X        amidst_data = 1;
  2713. X      i++;
  2714. X    }
  2715. X    }
  2716. X  if (i == RECORDSIZE)
  2717. X    *to = i;
  2718. X  else
  2719. X    *to = save_to;
  2720. X
  2721. X}
  2722. X
  2723. X#endif
  2724. X
  2725. X/* Note that this routine is only called if zero_record returned true */
  2726. X#if 0                /* But we actually don't need it at all. */
  2727. Xwhere_is_data (from, to, buffer)
  2728. X     int *from, *to;
  2729. X     char *buffer;
  2730. X{
  2731. X  char *fp, *tp;
  2732. X
  2733. X  for (fp = buffer; !*fp; fp++)
  2734. X    ;
  2735. X  for (tp = buffer + RECORDSIZE - 1; !*tp; tp--)
  2736. X    ;
  2737. X  *from = fp - buffer;
  2738. X  *to = tp - buffer + 1;
  2739. X}
  2740. X
  2741. X#endif
  2742. X
  2743. X
  2744. X
  2745. X/*
  2746. X * Takes a recordful of data and basically cruises through it to see if
  2747. X * it's made *entirely* of zeros, returning a 0 the instant it finds
  2748. X * something that is a non-zero, i.e., useful data.
  2749. X */
  2750. Xint
  2751. Xzero_record (buffer)
  2752. X     char *buffer;
  2753. X{
  2754. X  register int i;
  2755. X
  2756. X  for (i = 0; i < RECORDSIZE; i++)
  2757. X    if (buffer[i] != '\000')
  2758. X      return 0;
  2759. X  return 1;
  2760. X}
  2761. X
  2762. Xvoid
  2763. Xfind_new_file_size (filesize, highest_index)
  2764. X     int *filesize;
  2765. X     int highest_index;
  2766. X{
  2767. X  register int i;
  2768. X
  2769. X  *filesize = 0;
  2770. X  for (i = 0; sparsearray[i].numbytes && i <= highest_index; i++)
  2771. X    *filesize += sparsearray[i].numbytes;
  2772. X}
  2773. X
  2774. X/*
  2775. X * Make a header block for the file  name  whose stat info is  st .
  2776. X * Return header pointer for success, NULL if the name is too long.
  2777. X */
  2778. Xunion record *
  2779. Xstart_header (name, st)
  2780. X     char *name;
  2781. X     register struct stat *st;
  2782. X{
  2783. X  register union record *header;
  2784. X
  2785. X  if (strlen (name) >= NAMSIZ)
  2786. X    write_long (name, LF_LONGNAME);
  2787. X
  2788. X  header = (union record *) findrec ();
  2789. X  bzero (header->charptr, sizeof (*header));    /* XXX speed up */
  2790. X
  2791. X  /*
  2792. X     * Check the file name and put it in the record.
  2793. X     */
  2794. X  if (!f_absolute_paths)
  2795. X    {
  2796. X      static int warned_once = 0;
  2797. X#ifdef __MSDOS__
  2798. X      if (name[1] == ':')
  2799. X    {
  2800. X      name += 2;
  2801. X      if (!warned_once++)
  2802. X        msg ("Removing drive spec from names in the archive");
  2803. X    }
  2804. X#endif
  2805. X      while ('/' == *name)
  2806. X    {
  2807. X      name++;        /* Force relative path */
  2808. X      if (!warned_once++)
  2809. X        msg ("Removing leading / from absolute path names in the archive.");
  2810. X    }
  2811. X    }
  2812. X  current_file_name = name;
  2813. X  strncpy (header->header.arch_name, name, NAMSIZ);
  2814. X  header->header.arch_name[NAMSIZ - 1] = '\0';
  2815. X
  2816. X  to_oct ((long) (f_oldarch ? (st->st_mode & 07777) : st->st_mode),
  2817. X      8, header->header.mode);
  2818. X  to_oct ((long) st->st_uid, 8, header->header.uid);
  2819. X  to_oct ((long) st->st_gid, 8, header->header.gid);
  2820. X  to_oct ((long) st->st_size, 1 + 12, header->header.size);
  2821. X  to_oct ((long) st->st_mtime, 1 + 12, header->header.mtime);
  2822. X  /* header->header.linkflag is left as null */
  2823. X  if (f_gnudump)
  2824. X    {
  2825. X      to_oct ((long) st->st_atime, 1 + 12, header->header.atime);
  2826. X      to_oct ((long) st->st_ctime, 1 + 12, header->header.ctime);
  2827. X    }
  2828. X
  2829. X#ifndef NONAMES
  2830. X  /* Fill in new Unix Standard fields if desired. */
  2831. X  if (f_standard)
  2832. X    {
  2833. X      header->header.linkflag = LF_NORMAL;    /* New default */
  2834. X      strcpy (header->header.magic, TMAGIC);    /* Mark as Unix Std */
  2835. X      finduname (header->header.uname, st->st_uid);
  2836. X      findgname (header->header.gname, st->st_gid);
  2837. X    }
  2838. X#endif
  2839. X  return header;
  2840. X}
  2841. X
  2842. X/*
  2843. X * Finish off a filled-in header block and write it out.
  2844. X * We also print the file name and/or full info if verbose is on.
  2845. X */
  2846. Xvoid
  2847. Xfinish_header (header)
  2848. X     register union record *header;
  2849. X{
  2850. X  register int i, sum;
  2851. X  register char *p;
  2852. X
  2853. X  bcopy (CHKBLANKS, header->header.chksum, sizeof (header->header.chksum));
  2854. X
  2855. X  sum = 0;
  2856. X  p = header->charptr;
  2857. X  for (i = sizeof (*header); --i >= 0;)
  2858. X    {
  2859. X      /*
  2860. X         * We can't use unsigned char here because of old compilers,
  2861. X         * e.g. V7.
  2862. X         */
  2863. X      sum += 0xFF & *p++;
  2864. X    }
  2865. X
  2866. X  /*
  2867. X     * Fill in the checksum field.  It's formatted differently
  2868. X     * from the other fields:  it has [6] digits, a null, then a
  2869. X     * space -- rather than digits, a space, then a null.
  2870. X     * We use to_oct then write the null in over to_oct's space.
  2871. X     * The final space is already there, from checksumming, and
  2872. X     * to_oct doesn't modify it.
  2873. X     *
  2874. X     * This is a fast way to do:
  2875. X     * (void) sprintf(header->header.chksum, "%6o", sum);
  2876. X     */
  2877. X  to_oct ((long) sum, 8, header->header.chksum);
  2878. X  header->header.chksum[6] = '\0';    /* Zap the space */
  2879. X
  2880. X  userec (header);
  2881. X
  2882. X  if (f_verbose)
  2883. X    {
  2884. X      extern union record *head;/* Points to current tape header */
  2885. X      extern int head_standard;    /* Tape header is in ANSI format */
  2886. X
  2887. X      /* These globals are parameters to print_header, sigh */
  2888. X      head = header;
  2889. X      /* hstat is already set up */
  2890. X      head_standard = f_standard;
  2891. X      print_header ();
  2892. X    }
  2893. X
  2894. X  return;
  2895. X}
  2896. X
  2897. X
  2898. X/*
  2899. X * Quick and dirty octal conversion.
  2900. X * Converts long "value" into a "digs"-digit field at "where",
  2901. X * including a trailing space and room for a null.  "digs"==3 means
  2902. X * 1 digit, a space, and room for a null.
  2903. X *
  2904. X * We assume the trailing null is already there and don't fill it in.
  2905. X * This fact is used by start_header and finish_header, so don't change it!
  2906. X *
  2907. X * This should be equivalent to:
  2908. X *    (void) sprintf(where, "%*lo ", digs-2, value);
  2909. X * except that sprintf fills in the trailing null and we don't.
  2910. X */
  2911. Xvoid
  2912. Xto_oct (value, digs, where)
  2913. X     register long value;
  2914. X     register int digs;
  2915. X     register char *where;
  2916. X{
  2917. X
  2918. X  --digs;            /* Trailing null slot is left alone */
  2919. X  where[--digs] = ' ';        /* Put in the space, though */
  2920. X
  2921. X  /* Produce the digits -- at least one */
  2922. X  do
  2923. X    {
  2924. X      where[--digs] = '0' + (char) (value & 7);    /* one octal digit */
  2925. X      value >>= 3;
  2926. X    }
  2927. X  while (digs > 0 && value != 0);
  2928. X
  2929. X  /* Leading spaces, if necessary */
  2930. X  while (digs > 0)
  2931. X    where[--digs] = ' ';
  2932. X
  2933. X}
  2934. X
  2935. X
  2936. X/*
  2937. X * Write the EOT record(s).
  2938. X * We actually zero at least one record, through the end of the block.
  2939. X * Old tar writes garbage after two zeroed records -- and PDtar used to.
  2940. X */
  2941. Xvoid
  2942. Xwrite_eot ()
  2943. X{
  2944. X  union record *p;
  2945. X  int bufsize;
  2946. X
  2947. X  p = findrec ();
  2948. X  if (p)
  2949. X    {
  2950. X      bufsize = endofrecs ()->charptr - p->charptr;
  2951. X      bzero (p->charptr, bufsize);
  2952. X      userec (p);
  2953. X    }
  2954. X}
  2955. X
  2956. X/* Write a LF_LONGLINK or LF_LONGNAME record. */
  2957. Xvoid
  2958. Xwrite_long (p, type)
  2959. X     char *p;
  2960. X     char type;
  2961. X{
  2962. X  int size = strlen (p) + 1;
  2963. X  int bufsize;
  2964. X  union record *header;
  2965. X  struct stat foo;
  2966. X
  2967. X
  2968. X  bzero (&foo, sizeof foo);
  2969. X  foo.st_size = size;
  2970. X
  2971. X  header = start_header ("././@LongLink", &foo);
  2972. X  header->header.linkflag = type;
  2973. X  finish_header (header);
  2974. X
  2975. X  header = findrec ();
  2976. X
  2977. X  bufsize = endofrecs ()->charptr - header->charptr;
  2978. X
  2979. X  while (bufsize < size)
  2980. X    {
  2981. X      bcopy (p, header->charptr, bufsize);
  2982. X      p += bufsize;
  2983. X      size -= bufsize;
  2984. X      userec (header + (bufsize - 1) / RECORDSIZE);
  2985. X      header = findrec ();
  2986. X      bufsize = endofrecs ()->charptr - header->charptr;
  2987. X    }
  2988. X  bcopy (p, header->charptr, size);
  2989. X  bzero (header->charptr + size, bufsize - size);
  2990. X  userec (header + (size - 1) / RECORDSIZE);
  2991. X}
  2992. END_OF_FILE
  2993. if test 33888 -ne `wc -c <'create.c'`; then
  2994.     echo shar: \"'create.c'\" unpacked with wrong size!
  2995. fi
  2996. # end of 'create.c'
  2997. fi
  2998. if test -f 'extract.c' -a "${1}" != "-c" ; then 
  2999.   echo shar: Will not clobber existing file \"'extract.c'\"
  3000. else
  3001. echo shar: Extracting \"'extract.c'\" \(24051 characters\)
  3002. sed "s/^X//" >'extract.c' <<'END_OF_FILE'
  3003. X/* Extract files from a tar archive.
  3004. X   Copyright (C) 1988, 1992, 1993 Free Software Foundation
  3005. X
  3006. XThis file is part of GNU Tar.
  3007. X
  3008. XGNU Tar is free software; you can redistribute it and/or modify
  3009. Xit under the terms of the GNU General Public License as published by
  3010. Xthe Free Software Foundation; either version 2, or (at your option)
  3011. Xany later version.
  3012. X
  3013. XGNU Tar is distributed in the hope that it will be useful,
  3014. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  3015. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  3016. XGNU General Public License for more details.
  3017. X
  3018. XYou should have received a copy of the GNU General Public License
  3019. Xalong with GNU Tar; see the file COPYING.  If not, write to
  3020. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  3021. X
  3022. X/*
  3023. X * Extract files from a tar archive.
  3024. X *
  3025. X * Written 19 Nov 1985 by John Gilmore, ihnp4!hoptoad!gnu.
  3026. X */
  3027. X
  3028. X#include <stdio.h>
  3029. X#include <errno.h>
  3030. X#ifndef STDC_HEADERS
  3031. Xextern int errno;
  3032. X#endif
  3033. X#include <sys/types.h>
  3034. X#include <time.h>
  3035. Xtime_t time ();
  3036. X
  3037. X#ifdef BSD42
  3038. X#include <sys/file.h>
  3039. X#else
  3040. X#ifndef V7
  3041. X#include <fcntl.h>
  3042. X#endif
  3043. X#endif
  3044. X
  3045. X#ifdef NO_OPEN3
  3046. X/* We need the #define's even though we don't use them. */
  3047. X#include "open3.h"
  3048. X#endif
  3049. X
  3050. X#ifdef EMUL_OPEN3
  3051. X/* Simulated 3-argument open for systems that don't have it */
  3052. X#include "open3.h"
  3053. X#endif
  3054. X
  3055. X#include "tar.h"
  3056. X#include "port.h"
  3057. X
  3058. X#if defined(_POSIX_VERSION)
  3059. X#include <utime.h>
  3060. X#else
  3061. Xstruct utimbuf
  3062. X{
  3063. X  long actime;
  3064. X  long modtime;
  3065. X};
  3066. X
  3067. X#endif
  3068. X
  3069. Xextern FILE *msg_file;
  3070. X
  3071. Xextern union record *head;    /* Points to current tape header */
  3072. Xextern struct stat hstat;    /* Stat struct corresponding */
  3073. Xextern int head_standard;    /* Tape header is in ANSI format */
  3074. X
  3075. Xextern char *save_name;
  3076. Xextern long save_totsize;
  3077. Xextern long save_sizeleft;
  3078. X
  3079. Xint confirm ();
  3080. Xvoid decode_header ();
  3081. Xvoid extract_mangle ();
  3082. Xvoid extract_sparse_file ();
  3083. Xlong from_oct ();
  3084. Xvoid gnu_restore ();
  3085. Xextern void print_header ();
  3086. Xextern void skip_file ();
  3087. Xextern void skip_extended_headers ();
  3088. Xextern void pr_mkdir ();
  3089. Xvoid saverec ();
  3090. X
  3091. Xint make_dirs ();        /* Makes required directories */
  3092. X
  3093. Xstatic time_t now = 0;        /* Current time */
  3094. Xstatic we_are_root = 0;        /* True if our effective uid == 0 */
  3095. Xstatic int notumask = ~0;    /* Masks out bits user doesn't want */
  3096. X
  3097. X/*
  3098. X * "Scratch" space to store the information about a sparse file before
  3099. X * writing the info into the header or extended header
  3100. X */
  3101. X/*struct sp_array    *sparsearray;*/
  3102. X
  3103. X/* number of elts storable in the sparsearray */
  3104. X/*int    sp_array_size = 10;*/
  3105. X
  3106. Xstruct saved_dir_info
  3107. X{
  3108. X  char *path;
  3109. X  int mode;
  3110. X  int atime;
  3111. X  int mtime;
  3112. X  struct saved_dir_info *next;
  3113. X};
  3114. X
  3115. Xstruct saved_dir_info *saved_dir_info_head;
  3116. X
  3117. X/*
  3118. X * Set up to extract files.
  3119. X */
  3120. Xvoid
  3121. Xextr_init ()
  3122. X{
  3123. X  int ourmask;
  3124. X
  3125. X  now = time ((time_t *) 0);
  3126. X  if (geteuid () == 0)
  3127. X    we_are_root = 1;
  3128. X
  3129. X  /*
  3130. X     * We need to know our umask.  But if f_use_protection is set,
  3131. X     * leave our kernel umask at 0, and our "notumask" at ~0.
  3132. X     */
  3133. X  ourmask = umask (0);        /* Read it */
  3134. X  if (!f_use_protection)
  3135. X    {
  3136. X      (void) umask (ourmask);    /* Set it back how it was */
  3137. X      notumask = ~ourmask;    /* Make umask override permissions */
  3138. X    }
  3139. X}
  3140. X
  3141. X
  3142. X/*
  3143. X * Extract a file from the archive.
  3144. X */
  3145. Xvoid
  3146. Xextract_archive ()
  3147. X{
  3148. X  register char *data;
  3149. X  int fd, check, namelen, written, openflag;
  3150. X  long size;
  3151. X  struct utimbuf acc_upd_times;
  3152. X  register int skipcrud;
  3153. X  register int i;
  3154. X  /*    int sparse_ind = 0;*/
  3155. X  union record *exhdr;
  3156. X  struct saved_dir_info *tmp;
  3157. X  /*    int end_nulls; */
  3158. X
  3159. X  saverec (&head);        /* Make sure it sticks around */
  3160. X  userec (head);        /* And go past it in the archive */
  3161. X  decode_header (head, &hstat, &head_standard, 1);    /* Snarf fields */
  3162. X
  3163. X  if (f_confirm && !confirm ("extract", current_file_name))
  3164. X    {
  3165. X      if (head->header.isextended)
  3166. X    skip_extended_headers ();
  3167. X      skip_file ((long) hstat.st_size);
  3168. X      saverec ((union record **) 0);
  3169. X      return;
  3170. X    }
  3171. X
  3172. X  /* Print the record from 'head' and 'hstat' */
  3173. X  if (f_verbose)
  3174. X    print_header ();
  3175. X
  3176. X  /*
  3177. X     * Check for fully specified pathnames and other atrocities.
  3178. X     *
  3179. X     * Note, we can't just make a pointer to the new file name,
  3180. X     * since saverec() might move the header and adjust "head".
  3181. X     * We have to start from "head" every time we want to touch
  3182. X     * the header record.
  3183. X     */
  3184. X  skipcrud = 0;
  3185. X  while (!f_absolute_paths
  3186. X     && '/' == current_file_name[skipcrud])
  3187. X    {
  3188. X      static int warned_once = 0;
  3189. X
  3190. X      skipcrud++;        /* Force relative path */
  3191. X      if (!warned_once++)
  3192. X    {
  3193. X      msg ("Removing leading / from absolute path names in the archive.");
  3194. X    }
  3195. X    }
  3196. X
  3197. X  switch (head->header.linkflag)
  3198. X    {
  3199. X
  3200. X    default:
  3201. X      msg ("Unknown file type '%c' for %s, extracted as normal file",
  3202. X       head->header.linkflag, skipcrud + current_file_name);
  3203. X      /* FALL THRU */
  3204. X
  3205. X      /*
  3206. X      * JK - What we want to do if the file is sparse is loop through
  3207. X      * the array of sparse structures in the header and read in
  3208. X      * and translate the character strings representing  1) the offset
  3209. X      * at which to write and 2) how many bytes to write into numbers,
  3210. X      * which we store into the scratch array, "sparsearray".  This
  3211. X      * array makes our life easier the same way it did in creating
  3212. X      * the tar file that had to deal with a sparse file.
  3213. X      *
  3214. X      * After we read in the first five (at most) sparse structures,
  3215. X      * we check to see if the file has an extended header, i.e.,
  3216. X      * if more sparse structures are needed to describe the contents
  3217. X      * of the new file.  If so, we read in the extended headers
  3218. X      * and continue to store their contents into the sparsearray.
  3219. X      */
  3220. X    case LF_SPARSE:
  3221. X      sp_array_size = 10;
  3222. X      sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
  3223. X      for (i = 0; i < SPARSE_IN_HDR; i++)
  3224. X    {
  3225. X      sparsearray[i].offset =
  3226. X        from_oct (1 + 12, head->header.sp[i].offset);
  3227. X      sparsearray[i].numbytes =
  3228. X        from_oct (1 + 12, head->header.sp[i].numbytes);
  3229. X      if (!sparsearray[i].numbytes)
  3230. X        break;
  3231. X    }
  3232. X
  3233. X      /*        end_nulls = from_oct(1+12, head->header.ending_blanks);*/
  3234. X
  3235. X      if (head->header.isextended)
  3236. X    {
  3237. X      /* read in the list of extended headers
  3238. X                and translate them into the sparsearray
  3239. X                as before */
  3240. X
  3241. X      /* static */ int ind = SPARSE_IN_HDR;
  3242. X
  3243. X      for (;;)
  3244. X        {
  3245. X
  3246. X          exhdr = findrec ();
  3247. X          for (i = 0; i < SPARSE_EXT_HDR; i++)
  3248. X        {
  3249. X
  3250. X          if (i + ind > sp_array_size - 1)
  3251. X            {
  3252. X              /*
  3253. X                      * realloc the scratch area
  3254. X                      * since we've run out of room --
  3255. X                      */
  3256. X              sparsearray = (struct sp_array *)
  3257. X            ck_realloc (sparsearray,
  3258. X                2 * sp_array_size * (sizeof (struct sp_array)));
  3259. X              sp_array_size *= 2;
  3260. X            }
  3261. X          if (!exhdr->ext_hdr.sp[i].numbytes)
  3262. X            break;
  3263. X          sparsearray[i + ind].offset =
  3264. X            from_oct (1 + 12, exhdr->ext_hdr.sp[i].offset);
  3265. X          sparsearray[i + ind].numbytes =
  3266. X            from_oct (1 + 12, exhdr->ext_hdr.sp[i].numbytes);
  3267. X        }
  3268. X          if (!exhdr->ext_hdr.isextended)
  3269. X        break;
  3270. X          else
  3271. X        {
  3272. X          ind += SPARSE_EXT_HDR;
  3273. X          userec (exhdr);
  3274. X        }
  3275. X        }
  3276. X      userec (exhdr);
  3277. X    }
  3278. X
  3279. X      /* FALL THRU */
  3280. X    case LF_OLDNORMAL:
  3281. X    case LF_NORMAL:
  3282. X    case LF_CONTIG:
  3283. X      /*
  3284. X          * Appears to be a file.
  3285. X          * See if it's really a directory.
  3286. X          */
  3287. X      namelen = strlen (skipcrud + current_file_name) - 1;
  3288. X      if (current_file_name[skipcrud + namelen] == '/')
  3289. X    goto really_dir;
  3290. X
  3291. X      /* FIXME, deal with protection issues */
  3292. X    again_file:
  3293. X      openflag = (f_keep ?
  3294. X          O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_EXCL :
  3295. X          O_BINARY | O_NDELAY | O_WRONLY | O_CREAT | O_TRUNC)
  3296. X    | ((head->header.linkflag == LF_SPARSE) ? 0 : O_APPEND);
  3297. X      /*
  3298. X              * JK - The last | is a kludge to solve the problem
  3299. X              * the O_APPEND flag  causes with files we are
  3300. X              * trying to make sparse:  when a file is opened
  3301. X              * with O_APPEND, it writes  to the last place
  3302. X              * that something was written, thereby ignoring
  3303. X              * any lseeks that we have done.  We add this
  3304. X              * extra condition to make it able to lseek when
  3305. X              * a file is sparse, i.e., we don't open the new
  3306. X              * file with this flag.  (Grump -- this bug caused
  3307. X              * me to waste a good deal of time, I might add)
  3308. X              */
  3309. X
  3310. X      if (f_exstdout)
  3311. X    {
  3312. X      fd = 1;
  3313. X      goto extract_file;
  3314. X    }
  3315. X#ifdef O_CTG
  3316. X      /*
  3317. X          * Contiguous files (on the Masscomp) have to specify
  3318. X          * the size in the open call that creates them.
  3319. X          */
  3320. X      if (head->header.linkflag == LF_CONTIG)
  3321. X    fd = open ((longname ? longname : head->header.name)
  3322. X           + skipcrud,
  3323. X           openflag | O_CTG,
  3324. X           hstat.st_mode, hstat.st_size);
  3325. X      else
  3326. X#endif
  3327. X    {
  3328. X#ifdef NO_OPEN3
  3329. X      /*
  3330. X              * On raw V7 we won't let them specify -k (f_keep), but
  3331. X              * we just bull ahead and create the files.
  3332. X              */
  3333. X      fd = creat ((longname
  3334. X               ? longname
  3335. X               : head->header.name) + skipcrud,
  3336. X              hstat.st_mode);
  3337. X#else
  3338. X      /*
  3339. X              * With 3-arg open(), we can do this up right.
  3340. X              */
  3341. X      fd = open (skipcrud + current_file_name,
  3342. X             openflag, hstat.st_mode);
  3343. X#endif
  3344. X    }
  3345. X
  3346. X      if (fd < 0)
  3347. X    {
  3348. X      if (make_dirs (skipcrud + current_file_name))
  3349. X        goto again_file;
  3350. X      msg_perror ("Could not create file %s",
  3351. X              skipcrud + current_file_name);
  3352. X      if (head->header.isextended)
  3353. X        skip_extended_headers ();
  3354. X      skip_file ((long) hstat.st_size);
  3355. X      goto quit;
  3356. X    }
  3357. X
  3358. X    extract_file:
  3359. X      if (head->header.linkflag == LF_SPARSE)
  3360. X    {
  3361. X      char *name;
  3362. X      int namelen;
  3363. X
  3364. X      /*
  3365. X              * Kludge alert.  NAME is assigned to header.name
  3366. X              * because during the extraction, the space that
  3367. X              * contains the header will get scribbled on, and
  3368. X              * the name will get munged, so any error messages
  3369. X              * that happen to contain the filename will look
  3370. X              * REAL interesting unless we do this.
  3371. X              */
  3372. X      namelen = strlen (skipcrud + current_file_name) + 1;
  3373. X      name = (char *) ck_malloc ((sizeof (char)) * namelen);
  3374. X      bcopy (skipcrud + current_file_name, name, namelen);
  3375. X      size = hstat.st_size;
  3376. X      extract_sparse_file (fd, &size, hstat.st_size, name);
  3377. X    }
  3378. X      else
  3379. X    for (size = hstat.st_size;
  3380. X         size > 0;
  3381. X         size -= written)
  3382. X      {
  3383. X
  3384. X        /*            long    offset,
  3385. X                 numbytes;*/
  3386. X
  3387. X        if (f_multivol)
  3388. X          {
  3389. X        save_name = current_file_name;
  3390. X        save_totsize = hstat.st_size;
  3391. X        save_sizeleft = size;
  3392. X          }
  3393. X
  3394. X        /*
  3395. X              * Locate data, determine max length
  3396. X              * writeable, write it, record that
  3397. X              * we have used the data, then check
  3398. X              * if the write worked.
  3399. X              */
  3400. X        data = findrec ()->charptr;
  3401. X        if (data == NULL)
  3402. X          {            /* Check it... */
  3403. X        msg ("Unexpected EOF on archive file");
  3404. X        break;
  3405. X          }
  3406. X        /*
  3407. X              * JK - If the file is sparse, use the sparsearray
  3408. X              * that we created before to lseek into the new
  3409. X              * file the proper amount, and to see how many
  3410. X              * bytes we want to write at that position.
  3411. X              */
  3412. X        /*            if (head->header.linkflag == LF_SPARSE) {
  3413. X                 off_t pos;
  3414. X
  3415. X                 pos = lseek(fd, (off_t) sparsearray[sparse_ind].offset, 0);
  3416. X                 printf("%d at %d\n", (int) pos, sparse_ind);
  3417. X                 written = sparsearray[sparse_ind++].numbytes;
  3418. X             } else*/
  3419. X        written = endofrecs ()->charptr - data;
  3420. X        if (written > size)
  3421. X          written = size;
  3422. X        errno = 0;
  3423. X        check = write (fd, data, written);
  3424. X        /*
  3425. X              * The following is in violation of strict
  3426. X              * typing, since the arg to userec
  3427. X              * should be a struct rec *.  FIXME.
  3428. X              */
  3429. X        userec ((union record *) (data + written - 1));
  3430. X        if (check == written)
  3431. X          continue;
  3432. X        /*
  3433. X              * Error in writing to file.
  3434. X              * Print it, skip to next file in archive.
  3435. X              */
  3436. X        if (check < 0)
  3437. X          msg_perror ("couldn't write to file %s",
  3438. X              skipcrud + current_file_name);
  3439. X        else
  3440. X          msg ("could only write %d of %d bytes to file %s",
  3441. X           check, written, skipcrud + current_file_name);
  3442. X        skip_file ((long) (size - written));
  3443. X        break;        /* Still do the close, mod time, chmod, etc */
  3444. X      }
  3445. X
  3446. X      if (f_multivol)
  3447. X    save_name = 0;
  3448. X
  3449. X      /* If writing to stdout, don't try to do anything
  3450. X                to the filename; it doesn't exist, or we don't
  3451. X                want to touch it anyway */
  3452. X      if (f_exstdout)
  3453. X    break;
  3454. X
  3455. X      /*        if (head->header.isextended) {
  3456. X             register union record *exhdr;
  3457. X             register int i;
  3458. X
  3459. X             for (i = 0; i < 21; i++) {
  3460. X                 long offset;
  3461. X
  3462. X                 if (!exhdr->ext_hdr.sp[i].numbytes)
  3463. X                     break;
  3464. X                 offset = from_oct(1+12,
  3465. X                         exhdr->ext_hdr.sp[i].offset);
  3466. X                 written = from_oct(1+12,
  3467. X                         exhdr->ext_hdr.sp[i].numbytes);
  3468. X                 lseek(fd, offset, 0);
  3469. X                 check = write(fd, data, written);
  3470. X                 if (check == written) continue;
  3471. X
  3472. X             }
  3473. X
  3474. X
  3475. X         }*/
  3476. X      check = close (fd);
  3477. X      if (check < 0)
  3478. X    {
  3479. X      msg_perror ("Error while closing %s",
  3480. X              skipcrud + current_file_name);
  3481. X    }
  3482. X
  3483. X
  3484. X    set_filestat:
  3485. X
  3486. X      /*
  3487. X          * If we are root, set the owner and group of the extracted
  3488. X          * file.  This does what is wanted both on real Unix and on
  3489. X          * System V.  If we are running as a user, we extract as that
  3490. X          * user; if running as root, we extract as the original owner.
  3491. X          */
  3492. X      if (we_are_root || f_do_chown)
  3493. X    {
  3494. X      if (chown (skipcrud + current_file_name,
  3495. X             hstat.st_uid, hstat.st_gid) < 0)
  3496. X        {
  3497. X          msg_perror ("cannot chown file %s to uid %d gid %d",
  3498. X              skipcrud + current_file_name,
  3499. X              hstat.st_uid, hstat.st_gid);
  3500. X        }
  3501. X    }
  3502. X
  3503. X      /*
  3504. X       * Set the modified time of the file.
  3505. X       *
  3506. X       * Note that we set the accessed time to "now", which
  3507. X       * is really "the time we started extracting files".
  3508. X       * unless f_gnudump is used, in which case .st_atime is used
  3509. X       */
  3510. X      if (!f_modified)
  3511. X    {
  3512. X      /* fixme if f_gnudump should set ctime too, but how? */
  3513. X      if (f_gnudump)
  3514. X        acc_upd_times.actime = hstat.st_atime;
  3515. X      else
  3516. X        acc_upd_times.actime = now;    /* Accessed now */
  3517. X      acc_upd_times.modtime = hstat.st_mtime;    /* Mod'd */
  3518. X      if (utime (skipcrud + current_file_name,
  3519. X             &acc_upd_times) < 0)
  3520. X        {
  3521. X          msg_perror ("couldn't change access and modification times of %s", skipcrud + current_file_name);
  3522. X        }
  3523. X    }
  3524. X      /* We do the utime before the chmod because some versions of
  3525. X           utime are broken and trash the modes of the file.  Since
  3526. X           we then change the mode anyway, we don't care. . . */
  3527. X
  3528. X      /*
  3529. X         * If '-k' is not set, open() or creat() could have saved
  3530. X         * the permission bits from a previously created file,
  3531. X         * ignoring the ones we specified.
  3532. X         * Even if -k is set, if the file has abnormal
  3533. X         * mode bits, we must chmod since writing or chown() has
  3534. X         * probably reset them.
  3535. X         *
  3536. X         * If -k is set, we know *we* created this file, so the mode
  3537. X         * bits were set by our open().   If the file is "normal", we
  3538. X         * skip the chmod.  This works because we did umask(0) if -p
  3539. X         * is set, so umask will have left the specified mode alone.
  3540. X         */
  3541. X      if ((!f_keep)
  3542. X      || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
  3543. X    {
  3544. X      if (chmod (skipcrud + current_file_name,
  3545. X             notumask & (int) hstat.st_mode) < 0)
  3546. X        {
  3547. X          msg_perror ("cannot change mode of file %s to %ld",
  3548. X              skipcrud + current_file_name,
  3549. X              notumask & (int) hstat.st_mode);
  3550. X        }
  3551. X    }
  3552. X
  3553. X    quit:
  3554. X      break;
  3555. X
  3556. X    case LF_LINK:
  3557. X    again_link:
  3558. X      {
  3559. X    struct stat st1, st2;
  3560. X
  3561. X    check = link (current_link_name, skipcrud + current_file_name);
  3562. X
  3563. X    if (check == 0)
  3564. X      break;
  3565. X    if (make_dirs (skipcrud + current_file_name))
  3566. X      goto again_link;
  3567. X    if (f_gnudump && errno == EEXIST)
  3568. X      break;
  3569. X    if (stat (current_link_name, &st1) == 0
  3570. X        && stat (current_file_name + skipcrud, &st2) == 0
  3571. X        && st1.st_dev == st2.st_dev
  3572. X        && st1.st_ino == st2.st_ino)
  3573. X      break;
  3574. X    msg_perror ("Could not link %s to %s",
  3575. X            skipcrud + current_file_name,
  3576. X            current_link_name);
  3577. X      }
  3578. X      break;
  3579. X
  3580. X#ifdef S_ISLNK
  3581. X    case LF_SYMLINK:
  3582. X    again_symlink:
  3583. X      check = symlink (current_link_name,
  3584. X               skipcrud + current_file_name);
  3585. X      /* FIXME, don't worry uid, gid, etc... */
  3586. X      if (check == 0)
  3587. X    break;
  3588. X      if (make_dirs (current_file_name + skipcrud))
  3589. X    goto again_symlink;
  3590. X      msg_perror ("Could not create symlink to %s",
  3591. X          current_link_name);
  3592. X      break;
  3593. X#endif
  3594. X
  3595. X#ifdef S_IFCHR
  3596. X    case LF_CHR:
  3597. X      hstat.st_mode |= S_IFCHR;
  3598. X      goto make_node;
  3599. X#endif
  3600. X
  3601. X#ifdef S_IFBLK
  3602. X    case LF_BLK:
  3603. X      hstat.st_mode |= S_IFBLK;
  3604. X#endif
  3605. X#if defined(S_IFCHR) || defined(S_IFBLK)
  3606. X    make_node:
  3607. X      check = mknod (current_file_name + skipcrud,
  3608. X             (int) hstat.st_mode, (int) hstat.st_rdev);
  3609. X      if (check != 0)
  3610. X    {
  3611. X      if (make_dirs (skipcrud + current_file_name))
  3612. X        goto make_node;
  3613. X      msg_perror ("Could not make %s",
  3614. X              current_file_name + skipcrud);
  3615. X      break;
  3616. X    };
  3617. X      goto set_filestat;
  3618. X#endif
  3619. X
  3620. X#ifdef S_ISFIFO
  3621. X      /* If local system doesn't support FIFOs, use default case */
  3622. X    case LF_FIFO:
  3623. X    make_fifo:
  3624. X      check = mkfifo (current_file_name + skipcrud,
  3625. X              (int) hstat.st_mode);
  3626. X      if (check != 0)
  3627. X    {
  3628. X      if (make_dirs (current_file_name + skipcrud))
  3629. X        goto make_fifo;
  3630. X      msg_perror ("Could not make %s",
  3631. X              skipcrud + current_file_name);
  3632. X      break;
  3633. X    };
  3634. X      goto set_filestat;
  3635. X#endif
  3636. X
  3637. X    case LF_DIR:
  3638. X    case LF_DUMPDIR:
  3639. X      namelen = strlen (current_file_name + skipcrud) - 1;
  3640. X    really_dir:
  3641. X      /* Check for trailing /, and zap as many as we find. */
  3642. X      while (namelen
  3643. X         && current_file_name[skipcrud + namelen] == '/')
  3644. X    current_file_name[skipcrud + namelen--] = '\0';
  3645. X      if (f_gnudump)
  3646. X    {            /* Read the entry and delete files
  3647. X                       that aren't listed in the archive */
  3648. X      gnu_restore (skipcrud);
  3649. X
  3650. X    }
  3651. X      else if (head->header.linkflag == LF_DUMPDIR)
  3652. X    skip_file ((long) (hstat.st_size));
  3653. X
  3654. X
  3655. X    again_dir:
  3656. X      check = mkdir (skipcrud + current_file_name,
  3657. X             (we_are_root ? 0 : 0300) | (int) hstat.st_mode);
  3658. X      if (check != 0)
  3659. X    {
  3660. X      struct stat st1;
  3661. X
  3662. X      if (make_dirs (skipcrud + current_file_name))
  3663. X        goto again_dir;
  3664. X      /* If we're trying to create '.', let it be. */
  3665. X      if (current_file_name[skipcrud + namelen] == '.' &&
  3666. X          (namelen == 0 ||
  3667. X           current_file_name[skipcrud + namelen - 1] == '/'))
  3668. X        goto check_perms;
  3669. X      if (errno == EEXIST
  3670. X          && stat (skipcrud + current_file_name, &st1) == 0
  3671. X          && (S_ISDIR (st1.st_mode)))
  3672. X        break;
  3673. X      msg_perror ("Could not create directory %s", skipcrud + current_file_name);
  3674. X      break;
  3675. X    }
  3676. X
  3677. X    check_perms:
  3678. X      if (!we_are_root && 0300 != (0300 & (int) hstat.st_mode))
  3679. X    {
  3680. X      hstat.st_mode |= 0300;
  3681. X      msg ("Added write and execute permission to directory %s",
  3682. X           skipcrud + current_file_name);
  3683. X    }
  3684. X
  3685. X      /*
  3686. X       * If we are root, set the owner and group of the extracted
  3687. X       * file.  This does what is wanted both on real Unix and on
  3688. X       * System V.  If we are running as a user, we extract as that
  3689. X       * user; if running as root, we extract as the original owner.
  3690. X       */
  3691. X      if (we_are_root || f_do_chown)
  3692. X    {
  3693. X      if (chown (skipcrud + current_file_name,
  3694. X             hstat.st_uid, hstat.st_gid) < 0)
  3695. X        {
  3696. X          msg_perror ("cannot chown file %s to uid %d gid %d",
  3697. X              skipcrud + current_file_name,
  3698. X              hstat.st_uid, hstat.st_gid);
  3699. X        }
  3700. X    }
  3701. X
  3702. X      if (!f_modified)
  3703. X    {
  3704. X      tmp = ((struct saved_dir_info *) 
  3705. X         ck_malloc (sizeof (struct saved_dir_info)));
  3706. X      tmp->path = (char *) ck_malloc (strlen (skipcrud 
  3707. X                          + current_file_name) + 1);
  3708. X      strcpy (tmp->path, skipcrud + current_file_name);
  3709. X      tmp->mode = hstat.st_mode;
  3710. X      tmp->atime = hstat.st_atime;
  3711. X      tmp->mtime = hstat.st_mtime;
  3712. X      tmp->next = saved_dir_info_head;
  3713. X      saved_dir_info_head = tmp;
  3714. X    }
  3715. X      else
  3716. X    {
  3717. X      /* This functions exactly as the code for set_filestat above. */
  3718. X      if ((!f_keep)
  3719. X          || (hstat.st_mode & (S_ISUID | S_ISGID | S_ISVTX)))
  3720. X        {
  3721. X          if (chmod (skipcrud + current_file_name,
  3722. X             notumask & (int) hstat.st_mode) < 0)
  3723. X        {
  3724. X          msg_perror ("cannot change mode of file %s to %ld",
  3725. X                  skipcrud + current_file_name,
  3726. X                  notumask & (int) hstat.st_mode);
  3727. X        }
  3728. X        }
  3729. X    }
  3730. X      break;
  3731. X
  3732. X    case LF_VOLHDR:
  3733. X      if (f_verbose)
  3734. X    {
  3735. X      printf ("Reading %s\n", current_file_name);
  3736. X    }
  3737. X      break;
  3738. X
  3739. X    case LF_NAMES:
  3740. X      extract_mangle (head);
  3741. X      break;
  3742. X
  3743. X    case LF_MULTIVOL:
  3744. X      msg ("Can't extract '%s'--file is continued from another volume\n", current_file_name);
  3745. X      skip_file ((long) hstat.st_size);
  3746. X      break;
  3747. X
  3748. X    case LF_LONGNAME:
  3749. X    case LF_LONGLINK:
  3750. X      msg ("Visible long name error\n");
  3751. X      skip_file ((long) hstat.st_size);
  3752. X      break;
  3753. X    }
  3754. X
  3755. X  /* We don't need to save it any longer. */
  3756. X  saverec ((union record **) 0);/* Unsave it */
  3757. X}
  3758. X
  3759. X/*
  3760. X * After a file/link/symlink/dir creation has failed, see if
  3761. X * it's because some required directory was not present, and if
  3762. X * so, create all required dirs.
  3763. X */
  3764. Xint
  3765. Xmake_dirs (pathname)
  3766. X     char *pathname;
  3767. X{
  3768. X  char *p;            /* Points into path */
  3769. X  int madeone = 0;        /* Did we do anything yet? */
  3770. X  int save_errno = errno;    /* Remember caller's errno */
  3771. X  int check;
  3772. X
  3773. X  if (errno != ENOENT)
  3774. X    return 0;            /* Not our problem */
  3775. X
  3776. X  for (p = index (pathname, '/'); p != NULL; p = index (p + 1, '/'))
  3777. X    {
  3778. X      /* Avoid mkdir of empty string, if leading or double '/' */
  3779. X      if (p == pathname || p[-1] == '/')
  3780. X    continue;
  3781. X      /* Avoid mkdir where last part of path is '.' */
  3782. X      if (p[-1] == '.' && (p == pathname + 1 || p[-2] == '/'))
  3783. X    continue;
  3784. X      *p = 0;            /* Truncate the path there */
  3785. X      check = mkdir (pathname, 0777);    /* Try to create it as a dir */
  3786. X      if (check == 0)
  3787. X    {
  3788. X      /* Fix ownership */
  3789. X      if (we_are_root)
  3790. X        {
  3791. X          if (chown (pathname, hstat.st_uid,
  3792. X             hstat.st_gid) < 0)
  3793. X        {
  3794. X          msg_perror ("cannot change owner of %s to uid %d gid %d", pathname, hstat.st_uid, hstat.st_gid);
  3795. X        }
  3796. X        }
  3797. X      pr_mkdir (pathname, p - pathname, notumask & 0777);
  3798. X      madeone++;        /* Remember if we made one */
  3799. X      *p = '/';
  3800. X      continue;
  3801. X    }
  3802. X      *p = '/';
  3803. X      if (errno == EEXIST)    /* Directory already exists */
  3804. X    continue;
  3805. X      /*
  3806. X         * Some other error in the mkdir.  We return to the caller.
  3807. X         */
  3808. X      break;
  3809. X    }
  3810. X
  3811. X  errno = save_errno;        /* Restore caller's errno */
  3812. X  return madeone;        /* Tell them to retry if we made one */
  3813. X}
  3814. X
  3815. Xvoid
  3816. Xextract_sparse_file (fd, sizeleft, totalsize, name)
  3817. X     int fd;
  3818. X     long *sizeleft, totalsize;
  3819. X     char *name;
  3820. X{
  3821. X  /*    register char    *data;*/
  3822. X  union record *datarec;
  3823. X  int sparse_ind = 0;
  3824. X  int written, count;
  3825. X
  3826. X  /* assuming sizeleft is initially totalsize */
  3827. X
  3828. X
  3829. X  while (*sizeleft > 0)
  3830. X    {
  3831. X      datarec = findrec ();
  3832. X      if (datarec == NULL)
  3833. X    {
  3834. X      msg ("Unexpected EOF on archive file");
  3835. X      return;
  3836. X    }
  3837. X      lseek (fd, sparsearray[sparse_ind].offset, 0);
  3838. X      written = sparsearray[sparse_ind++].numbytes;
  3839. X      while (written > RECORDSIZE)
  3840. X    {
  3841. X      count = write (fd, datarec->charptr, RECORDSIZE);
  3842. X      if (count < 0)
  3843. X        msg_perror ("couldn't write to file %s", name);
  3844. X      written -= count;
  3845. X      *sizeleft -= count;
  3846. X      userec (datarec);
  3847. X      datarec = findrec ();
  3848. X    }
  3849. X
  3850. X      count = write (fd, datarec->charptr, written);
  3851. X
  3852. X      if (count < 0)
  3853. X    {
  3854. X      msg_perror ("couldn't write to file %s", name);
  3855. X    }
  3856. X      else if (count != written)
  3857. X    {
  3858. X      msg ("could only write %d of %d bytes to file %s", count, 
  3859. X           totalsize, name);
  3860. X      skip_file ((long) (*sizeleft));
  3861. X    }
  3862. X
  3863. X      written -= count;
  3864. X      *sizeleft -= count;
  3865. X      userec (datarec);
  3866. X    }
  3867. X  free (sparsearray);
  3868. X  /*    if (end_nulls) {
  3869. X        register int i;
  3870. X
  3871. X        printf("%d\n", (int) end_nulls);
  3872. X        for (i = 0; i < end_nulls; i++)
  3873. X            write(fd, "\000", 1);
  3874. X    }*/
  3875. X  userec (datarec);
  3876. X}
  3877. X
  3878. X/* Set back the utime and mode for all the extracted directories. */
  3879. Xvoid 
  3880. Xrestore_saved_dir_info ()
  3881. X{
  3882. X  struct utimbuf acc_upd_times;
  3883. X
  3884. X  while (saved_dir_info_head != NULL)
  3885. X    {
  3886. X      /* fixme if f_gnudump should set ctime too, but how? */
  3887. X      if (f_gnudump)
  3888. X    acc_upd_times.actime = saved_dir_info_head->atime;
  3889. X      else
  3890. X    acc_upd_times.actime = now;    /* Accessed now */
  3891. X      acc_upd_times.modtime = saved_dir_info_head->mtime;    /* Mod'd */
  3892. X      if (utime (saved_dir_info_head->path, &acc_upd_times) < 0)
  3893. X    {
  3894. X      msg_perror ("couldn't change access and modification times of %s",
  3895. X              saved_dir_info_head->path);
  3896. X    }
  3897. X      if ((!f_keep) || (saved_dir_info_head->mode & (S_ISUID | S_ISGID | S_ISVTX)))
  3898. X    {
  3899. X      if (chmod (saved_dir_info_head->path,
  3900. X             notumask & saved_dir_info_head->mode) < 0)
  3901. X        {
  3902. X          msg_perror ("cannot change mode of file %s to %ld",
  3903. X              saved_dir_info_head->path,
  3904. X              notumask & saved_dir_info_head->mode);
  3905. X        }
  3906. X    }
  3907. X      saved_dir_info_head = saved_dir_info_head->next;
  3908. X    }
  3909. X}
  3910. END_OF_FILE
  3911. if test 24051 -ne `wc -c <'extract.c'`; then
  3912.     echo shar: \"'extract.c'\" unpacked with wrong size!
  3913. fi
  3914. # end of 'extract.c'
  3915. fi
  3916. if test -f 'buffer.c' -a "${1}" != "-c" ; then 
  3917.   echo shar: Will not clobber existing file \"'buffer.c'\"
  3918. else
  3919. echo shar: Extracting \"'buffer.c'\" \(35194 characters\)
  3920. sed "s/^X//" >'buffer.c' <<'END_OF_FILE'
  3921. X/* Buffer management for tar.
  3922. X   Copyright (C) 1988, 1992, 1993 Free Software Foundation
  3923. X
  3924. XThis file is part of GNU Tar.
  3925. X
  3926. XGNU Tar is free software; you can redistribute it and/or modify
  3927. Xit under the terms of the GNU General Public License as published by
  3928. Xthe Free Software Foundation; either version 2, or (at your option)
  3929. Xany later version.
  3930. X
  3931. XGNU Tar is distributed in the hope that it will be useful,
  3932. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  3933. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  3934. XGNU General Public License for more details.
  3935. X
  3936. XYou should have received a copy of the GNU General Public License
  3937. Xalong with GNU Tar; see the file COPYING.  If not, write to
  3938. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  3939. X
  3940. X/*
  3941. X * Buffer management for tar.
  3942. X *
  3943. X * Written by John Gilmore, ihnp4!hoptoad!gnu, on 25 August 1985.
  3944. X */
  3945. X
  3946. X#include <stdio.h>
  3947. X#include <errno.h>
  3948. X#ifndef STDC_HEADERS
  3949. Xextern int errno;
  3950. X#endif
  3951. X#include <sys/types.h>        /* For non-Berkeley systems */
  3952. X#include <signal.h>
  3953. X#include <time.h>
  3954. Xtime_t time ();
  3955. X
  3956. X#ifdef HAVE_SYS_MTIO_H
  3957. X#include <sys/ioctl.h>
  3958. X#include <sys/mtio.h>
  3959. X#endif
  3960. X
  3961. X#ifdef BSD42
  3962. X#include <sys/file.h>
  3963. X#else
  3964. X#ifndef V7
  3965. X#include <fcntl.h>
  3966. X#endif
  3967. X#endif
  3968. X
  3969. X#ifdef    __MSDOS__
  3970. X#include <process.h>
  3971. X#endif
  3972. X
  3973. X#ifdef XENIX
  3974. X#include <sys/inode.h>
  3975. X#endif
  3976. X
  3977. X#include "tar.h"
  3978. X#include "port.h"
  3979. X#include "rmt.h"
  3980. X#include "regex.h"
  3981. X
  3982. X/* Either stdout or stderr:  The thing we write messages (standard msgs, not
  3983. X   errors) to.  Stdout unless we're writing a pipe, in which case stderr */
  3984. XFILE *msg_file = stdout;
  3985. X
  3986. X#define    STDIN    0        /* Standard input  file descriptor */
  3987. X#define    STDOUT    1        /* Standard output file descriptor */
  3988. X
  3989. X#define    PREAD    0        /* Read  file descriptor from pipe() */
  3990. X#define    PWRITE    1        /* Write file descriptor from pipe() */
  3991. X
  3992. X#define    MAGIC_STAT    105    /* Magic status returned by child, if
  3993. X                   it can't exec.  We hope compress/sh
  3994. X                   never return this status! */
  3995. X
  3996. Xvoid *valloc ();
  3997. X
  3998. Xvoid writeerror ();
  3999. Xvoid readerror ();
  4000. X
  4001. Xvoid ck_pipe ();
  4002. Xvoid ck_close ();
  4003. X
  4004. Xint backspace_output ();
  4005. Xextern void finish_header ();
  4006. Xvoid flush_archive ();
  4007. Xint isfile ();
  4008. Xint new_volume ();
  4009. Xvoid verify_volume ();
  4010. Xextern void to_oct ();
  4011. X
  4012. X#ifndef __MSDOS__
  4013. X/* Obnoxious test to see if dimwit is trying to dump the archive */
  4014. Xdev_t ar_dev;
  4015. Xino_t ar_ino;
  4016. X#endif
  4017. X
  4018. X/*
  4019. X * The record pointed to by save_rec should not be overlaid
  4020. X * when reading in a new tape block.  Copy it to record_save_area first, and
  4021. X * change the pointer in *save_rec to point to record_save_area.
  4022. X * Saved_recno records the record number at the time of the save.
  4023. X * This is used by annofile() to print the record number of a file's
  4024. X * header record.
  4025. X */
  4026. Xstatic union record **save_rec;
  4027. Xunion record record_save_area;
  4028. Xstatic long saved_recno;
  4029. X
  4030. X/*
  4031. X * PID of child program, if f_compress or remote archive access.
  4032. X */
  4033. Xstatic int childpid = 0;
  4034. X
  4035. X/*
  4036. X * Record number of the start of this block of records
  4037. X */
  4038. Xlong baserec;
  4039. X
  4040. X/*
  4041. X * Error recovery stuff
  4042. X */
  4043. Xstatic int r_error_count;
  4044. X
  4045. X/*
  4046. X * Have we hit EOF yet?
  4047. X */
  4048. Xstatic int hit_eof;
  4049. X
  4050. X/* Checkpointing counter */
  4051. Xstatic int checkpoint;
  4052. X
  4053. X/* JF we're reading, but we just read the last record and its time to update */
  4054. Xextern time_to_start_writing;
  4055. Xint file_to_switch_to = -1;    /* If remote update, close archive, and use
  4056. X                   this descriptor to write to */
  4057. X
  4058. Xstatic int volno = 1;        /* JF which volume of a multi-volume tape
  4059. X                   we're on */
  4060. Xstatic int global_volno = 1;    /* Volume number to print in external messages. */
  4061. X
  4062. Xchar *save_name = 0;        /* Name of the file we are currently writing */
  4063. Xlong save_totsize;        /* total size of file we are writing.  Only
  4064. X                   valid if save_name is non_zero */
  4065. Xlong save_sizeleft;        /* Where we are in the file we are writing.
  4066. X                   Only valid if save_name is non-zero */
  4067. X
  4068. Xint write_archive_to_stdout;
  4069. X
  4070. X/* Used by fl_read and fl_write to store the real info about saved names */
  4071. Xstatic char real_s_name[NAMSIZ];
  4072. Xstatic long real_s_totsize;
  4073. Xstatic long real_s_sizeleft;
  4074. X
  4075. X/* Reset the EOF flag (if set), and re-set ar_record, etc */
  4076. X
  4077. Xvoid
  4078. Xreset_eof ()
  4079. X{
  4080. X  if (hit_eof)
  4081. X    {
  4082. X      hit_eof = 0;
  4083. X      ar_record = ar_block;
  4084. X      ar_last = ar_block + blocking;
  4085. X      ar_reading = 0;
  4086. X    }
  4087. X}
  4088. X
  4089. X/*
  4090. X * Return the location of the next available input or output record.
  4091. X * Return NULL for EOF.  Once we have returned NULL, we just keep returning
  4092. X * it, to avoid accidentally going on to the next file on the "tape".
  4093. X */
  4094. Xunion record *
  4095. Xfindrec ()
  4096. X{
  4097. X  if (ar_record == ar_last)
  4098. X    {
  4099. X      if (hit_eof)
  4100. X    return (union record *) NULL;    /* EOF */
  4101. X      flush_archive ();
  4102. X      if (ar_record == ar_last)
  4103. X    {
  4104. X      hit_eof++;
  4105. X      return (union record *) NULL;    /* EOF */
  4106. X    }
  4107. X    }
  4108. X  return ar_record;
  4109. X}
  4110. X
  4111. X
  4112. X/*
  4113. X * Indicate that we have used all records up thru the argument.
  4114. X * (should the arg have an off-by-1? XXX FIXME)
  4115. X */
  4116. Xvoid
  4117. Xuserec (rec)
  4118. X     union record *rec;
  4119. X{
  4120. X  while (rec >= ar_record)
  4121. X    ar_record++;
  4122. X  /*
  4123. X     * Do NOT flush the archive here.  If we do, the same
  4124. X     * argument to userec() could mean the next record (if the
  4125. X     * input block is exactly one record long), which is not what
  4126. X     * is intended.
  4127. X     */
  4128. X  if (ar_record > ar_last)
  4129. X    abort ();
  4130. X}
  4131. X
  4132. X
  4133. X/*
  4134. X * Return a pointer to the end of the current records buffer.
  4135. X * All the space between findrec() and endofrecs() is available
  4136. X * for filling with data, or taking data from.
  4137. X */
  4138. Xunion record *
  4139. Xendofrecs ()
  4140. X{
  4141. X  return ar_last;
  4142. X}
  4143. X
  4144. X
  4145. X/*
  4146. X * Duplicate a file descriptor into a certain slot.
  4147. X * Equivalent to BSD "dup2" with error reporting.
  4148. X */
  4149. Xvoid
  4150. Xdupto (from, to, msg)
  4151. X     int from, to;
  4152. X     char *msg;
  4153. X{
  4154. X  int err;
  4155. X
  4156. X  if (from != to)
  4157. X    {
  4158. X      err = close (to);
  4159. X      if (err < 0 && errno != EBADF)
  4160. X    {
  4161. X      msg_perror ("Cannot close descriptor %d", to);
  4162. X      exit (EX_SYSTEM);
  4163. X    }
  4164. X      err = dup (from);
  4165. X      if (err != to)
  4166. X    {
  4167. X      msg_perror ("cannot dup %s", msg);
  4168. X      exit (EX_SYSTEM);
  4169. X    }
  4170. X      ck_close (from);
  4171. X    }
  4172. X}
  4173. X
  4174. X#ifdef __MSDOS__
  4175. Xvoid
  4176. Xchild_open ()
  4177. X{
  4178. X  fprintf (stderr, "MS-DOS %s can't use compressed or remote archives\n", tar);
  4179. X  exit (EX_ARGSBAD);
  4180. X}
  4181. X
  4182. X#else
  4183. Xvoid
  4184. Xchild_open ()
  4185. X{
  4186. X  int pipe[2];
  4187. X  int err = 0;
  4188. X
  4189. X  int kidpipe[2];
  4190. X  int kidchildpid;
  4191. X
  4192. X#define READ    0
  4193. X#define WRITE    1
  4194. X
  4195. X  ck_pipe (pipe);
  4196. X
  4197. X  childpid = fork ();
  4198. X  if (childpid < 0)
  4199. X    {
  4200. X      msg_perror ("cannot fork");
  4201. X      exit (EX_SYSTEM);
  4202. X    }
  4203. X  if (childpid > 0)
  4204. X    {
  4205. X      /* We're the parent.  Clean up and be happy */
  4206. X      /* This, at least, is easy */
  4207. X
  4208. X      if (ar_reading)
  4209. X    {
  4210. X      f_reblock++;
  4211. X      archive = pipe[READ];
  4212. X      ck_close (pipe[WRITE]);
  4213. X    }
  4214. X      else
  4215. X    {
  4216. X      archive = pipe[WRITE];
  4217. X      ck_close (pipe[READ]);
  4218. X    }
  4219. X      return;
  4220. X    }
  4221. X
  4222. X  /* We're the kid */
  4223. X  if (ar_reading)
  4224. X    {
  4225. X      dupto (pipe[WRITE], STDOUT, "(child) pipe to stdout");
  4226. X      ck_close (pipe[READ]);
  4227. X    }
  4228. X  else
  4229. X    {
  4230. X      dupto (pipe[READ], STDIN, "(child) pipe to stdin");
  4231. X      ck_close (pipe[WRITE]);
  4232. X    }
  4233. X
  4234. X  /* We need a child tar only if
  4235. X       1: we're reading/writing stdin/out (to force reblocking)
  4236. X       2: the file is to be accessed by rmt (compress doesn't know how)
  4237. X       3: the file is not a plain file */
  4238. X#ifdef NO_REMOTE
  4239. X  if (!(ar_files[0][0] == '-' && ar_files[0][1] == '\0') && isfile (ar_files[0]))
  4240. X#else
  4241. X  if (!(ar_files[0][0] == '-' && ar_files[0][1] == '\0') && !_remdev (ar_files[0]) && isfile (ar_files[0]))
  4242. X#endif
  4243. X    {
  4244. X      /* We don't need a child tar.  Open the archive */
  4245. X      if (ar_reading)
  4246. X    {
  4247. X      archive = open (ar_files[0], O_RDONLY | O_BINARY, 0666);
  4248. X      if (archive < 0)
  4249. X        {
  4250. X          msg_perror ("can't open archive %s", ar_files[0]);
  4251. X          exit (EX_BADARCH);
  4252. X        }
  4253. X      dupto (archive, STDIN, "archive to stdin");
  4254. X      /* close(archive); */
  4255. X    }
  4256. X      else
  4257. X    {
  4258. X      archive = creat (ar_files[0], 0666);
  4259. X      if (archive < 0)
  4260. X        {
  4261. X          msg_perror ("can't open archive %s", ar_files[0]);
  4262. X          exit (EX_BADARCH);
  4263. X        }
  4264. X      dupto (archive, STDOUT, "archive to stdout");
  4265. X      /* close(archive); */
  4266. X    }
  4267. X    }
  4268. X  else
  4269. X    {
  4270. X      /* We need a child tar */
  4271. X      ck_pipe (kidpipe);
  4272. X
  4273. X      kidchildpid = fork ();
  4274. X      if (kidchildpid < 0)
  4275. X    {
  4276. X      msg_perror ("child can't fork");
  4277. X      exit (EX_SYSTEM);
  4278. X    }
  4279. X
  4280. X      if (kidchildpid > 0)
  4281. X    {
  4282. X      /* About to exec compress:  set up the files */
  4283. X      if (ar_reading)
  4284. X        {
  4285. X          dupto (kidpipe[READ], STDIN, "((child)) pipe to stdin");
  4286. X          ck_close (kidpipe[WRITE]);
  4287. X          /* dup2(pipe[WRITE],STDOUT); */
  4288. X        }
  4289. X      else
  4290. X        {
  4291. X          /* dup2(pipe[READ],STDIN); */
  4292. X          dupto (kidpipe[WRITE], STDOUT, "((child)) pipe to stdout");
  4293. X          ck_close (kidpipe[READ]);
  4294. X        }
  4295. X      /* ck_close(pipe[READ]); */
  4296. X      /* ck_close(pipe[WRITE]); */
  4297. X      /* ck_close(kidpipe[READ]);
  4298. X            ck_close(kidpipe[WRITE]); */
  4299. X    }
  4300. X      else
  4301. X    {
  4302. X      /* Grandchild.  Do the right thing, namely sit here and
  4303. X           read/write the archive, and feed stuff back to compress */
  4304. X      tar = "tar (child)";
  4305. X      if (ar_reading)
  4306. X        {
  4307. X          dupto (kidpipe[WRITE], STDOUT, "[child] pipe to stdout");
  4308. X          ck_close (kidpipe[READ]);
  4309. X        }
  4310. X      else
  4311. X        {
  4312. X          dupto (kidpipe[READ], STDIN, "[child] pipe to stdin");
  4313. X          ck_close (kidpipe[WRITE]);
  4314. X        }
  4315. X
  4316. X      if (ar_files[0][0] == '-' && ar_files[0][1] == '\0')
  4317. X        {
  4318. X          if (ar_reading)
  4319. X        archive = STDIN;
  4320. X          else
  4321. X        archive = STDOUT;
  4322. X        }
  4323. X      else            /* This can't happen if (ar_reading==2)
  4324. X                archive = rmtopen(ar_files[0], O_RDWR|O_CREAT|O_BINARY, 0666);
  4325. X                        else */ if (ar_reading)
  4326. X        archive = rmtopen (ar_files[0], O_RDONLY | O_BINARY, 0666);
  4327. X      else
  4328. X        archive = rmtcreat (ar_files[0], 0666);
  4329. X
  4330. X      if (archive < 0)
  4331. X        {
  4332. X          msg_perror ("can't open archive %s", ar_files[0]);
  4333. X          exit (EX_BADARCH);
  4334. X        }
  4335. X
  4336. X      if (ar_reading)
  4337. X        {
  4338. X          for (;;)
  4339. X        {
  4340. X          char *ptr;
  4341. X          int max, count;
  4342. X
  4343. X          r_error_count = 0;
  4344. X        error_loop:
  4345. X          err = rmtread (archive, ar_block->charptr, (int) (blocksize));
  4346. X          if (err < 0)
  4347. X            {
  4348. X              readerror ();
  4349. X              goto error_loop;
  4350. X            }
  4351. X          if (err == 0)
  4352. X            break;
  4353. X          ptr = ar_block->charptr;
  4354. X          max = err;
  4355. X          while (max)
  4356. X            {
  4357. X              count = (max < RECORDSIZE) ? max : RECORDSIZE;
  4358. X              err = write (STDOUT, ptr, count);
  4359. X              if (err != count)
  4360. X            {
  4361. X              if (err < 0)
  4362. X                {
  4363. X                  msg_perror ("can't write to compression program");
  4364. X                  exit (EX_SYSTEM);
  4365. X                }
  4366. X              else
  4367. X                msg ("write to compression program short %d bytes",
  4368. X                 count - err);
  4369. X              count = (err < 0) ? 0 : err;
  4370. X            }
  4371. X              ptr += count;
  4372. X              max -= count;
  4373. X            }
  4374. X        }
  4375. X        }
  4376. X      else
  4377. X        {
  4378. X          for (;;)
  4379. X        {
  4380. X          int n;
  4381. X          char *ptr;
  4382. X
  4383. X          n = blocksize;
  4384. X          ptr = ar_block->charptr;
  4385. X          while (n)
  4386. X            {
  4387. X              err = read (STDIN, ptr, (n < RECORDSIZE) ? n : RECORDSIZE);
  4388. X              if (err <= 0)
  4389. X            break;
  4390. X              n -= err;
  4391. X              ptr += err;
  4392. X            }
  4393. X          /* EOF */
  4394. X          if (err == 0)
  4395. X            {
  4396. X              if (!f_compress_block)
  4397. X            blocksize -= n;
  4398. X              else
  4399. X            bzero (ar_block->charptr + blocksize - n, n);
  4400. X              err = rmtwrite (archive, ar_block->charptr, blocksize);
  4401. X              if (err != (blocksize))
  4402. X            writeerror (err);
  4403. X              if (!f_compress_block)
  4404. X            blocksize += n;
  4405. X              break;
  4406. X            }
  4407. X          if (n)
  4408. X            {
  4409. X              msg_perror ("can't read from compression program");
  4410. X              exit (EX_SYSTEM);
  4411. X            }
  4412. X          err = rmtwrite (archive, ar_block->charptr, (int) blocksize);
  4413. X          if (err != blocksize)
  4414. X            writeerror (err);
  4415. X        }
  4416. X        }
  4417. X
  4418. X      /* close_archive(); */
  4419. X      exit (0);
  4420. X    }
  4421. X    }
  4422. X  /* So we should exec compress (-d) */
  4423. X  if (ar_reading)
  4424. X    execlp (f_compressprog, f_compressprog, "-d", (char *) 0);
  4425. X  else
  4426. X    execlp (f_compressprog, f_compressprog, (char *) 0);
  4427. X  msg_perror ("can't exec %s", f_compressprog);
  4428. X  _exit (EX_SYSTEM);
  4429. X}
  4430. X
  4431. X
  4432. X/* return non-zero if p is the name of a directory */
  4433. Xint
  4434. Xisfile (p)
  4435. X     char *p;
  4436. X{
  4437. X  struct stat stbuf;
  4438. X
  4439. X  if (stat (p, &stbuf) < 0)
  4440. X    return 1;
  4441. X  if (S_ISREG (stbuf.st_mode))
  4442. X    return 1;
  4443. X  return 0;
  4444. X}
  4445. X
  4446. X#endif
  4447. X
  4448. X/*
  4449. X * Open an archive file.  The argument specifies whether we are
  4450. X * reading or writing.
  4451. X */
  4452. X/* JF if the arg is 2, open for reading and writing. */
  4453. Xvoid
  4454. Xopen_archive (reading)
  4455. X     int reading;
  4456. X{
  4457. X  msg_file = f_exstdout ? stderr : stdout;
  4458. X
  4459. X  if (blocksize == 0)
  4460. X    {
  4461. X      msg ("invalid value for blocksize");
  4462. X      exit (EX_ARGSBAD);
  4463. X    }
  4464. X
  4465. X  if (n_ar_files == 0)
  4466. X    {
  4467. X      msg ("No archive name given, what should I do?");
  4468. X      exit (EX_BADARCH);
  4469. X    }
  4470. X
  4471. X  /*NOSTRICT*/
  4472. X  if (f_multivol)
  4473. X    {
  4474. X      ar_block = (union record *) valloc ((unsigned) (blocksize + (2 * RECORDSIZE)));
  4475. X      if (ar_block)
  4476. X    ar_block += 2;
  4477. X    }
  4478. X  else
  4479. X    ar_block = (union record *) valloc ((unsigned) blocksize);
  4480. X  if (!ar_block)
  4481. X    {
  4482. X      msg ("could not allocate memory for blocking factor %d",
  4483. X       blocking);
  4484. X      exit (EX_ARGSBAD);
  4485. X    }
  4486. X
  4487. X  ar_record = ar_block;
  4488. X  ar_last = ar_block + blocking;
  4489. X  ar_reading = reading;
  4490. X
  4491. X  if (f_multivol && f_verify)
  4492. X    {
  4493. X      msg ("cannot verify multi-volume archives");
  4494. X      exit (EX_ARGSBAD);
  4495. X    }
  4496. X
  4497. X  if (f_compressprog)
  4498. X    {
  4499. X      if (reading == 2 || f_verify)
  4500. X    {
  4501. X      msg ("cannot update or verify compressed archives");
  4502. X      exit (EX_ARGSBAD);
  4503. X    }
  4504. X      if (f_multivol)
  4505. X    {
  4506. X      msg ("cannot use multi-volume compressed archives");
  4507. X      exit (EX_ARGSBAD);
  4508. X    }
  4509. X      child_open ();
  4510. X      if (!reading && ar_files[0][0] == '-' && ar_files[0][1] == '\0')
  4511. X    msg_file = stderr;
  4512. X      /* child_open(rem_host, rem_file); */
  4513. X    }
  4514. X  else if (ar_files[0][0] == '-' && ar_files[0][1] == '\0')
  4515. X    {
  4516. X      f_reblock++;        /* Could be a pipe, be safe */
  4517. X      if (f_verify)
  4518. X    {
  4519. X      msg ("can't verify stdin/stdout archive");
  4520. X      exit (EX_ARGSBAD);
  4521. X    }
  4522. X      if (reading == 2)
  4523. X    {
  4524. X      archive = STDIN;
  4525. X      msg_file = stderr;
  4526. X      write_archive_to_stdout++;
  4527. X    }
  4528. X      else if (reading)
  4529. X    archive = STDIN;
  4530. X      else
  4531. X    {
  4532. X      archive = STDOUT;
  4533. X      msg_file = stderr;
  4534. X    }
  4535. X    }
  4536. X  else if (reading == 2 || f_verify)
  4537. X    {
  4538. X      archive = rmtopen (ar_files[0], O_RDWR | O_CREAT | O_BINARY, 0666);
  4539. X    }
  4540. X  else if (reading)
  4541. X    {
  4542. X      archive = rmtopen (ar_files[0], O_RDONLY | O_BINARY, 0666);
  4543. X    }
  4544. X  else
  4545. X    {
  4546. X      archive = rmtcreat (ar_files[0], 0666);
  4547. X    }
  4548. X  if (archive < 0)
  4549. X    {
  4550. X      msg_perror ("can't open %s", ar_files[0]);
  4551. X      exit (EX_BADARCH);
  4552. X    }
  4553. X#ifndef __MSDOS__
  4554. X  if (!_isrmt (archive))
  4555. X    {
  4556. X      struct stat tmp_stat;
  4557. X
  4558. X      fstat (archive, &tmp_stat);
  4559. X      if (S_ISREG (tmp_stat.st_mode))
  4560. X    {
  4561. X      ar_dev = tmp_stat.st_dev;
  4562. X      ar_ino = tmp_stat.st_ino;
  4563. X    }
  4564. X    }
  4565. X#endif
  4566. X
  4567. X#ifdef    __MSDOS__
  4568. X  setmode (archive, O_BINARY);
  4569. X#endif
  4570. X
  4571. X  if (reading)
  4572. X    {
  4573. X      ar_last = ar_block;    /* Set up for 1st block = # 0 */
  4574. X      (void) findrec ();    /* Read it in, check for EOF */
  4575. X
  4576. X      if (f_volhdr)
  4577. X    {
  4578. X      union record *head;
  4579. X#if 0
  4580. X      char *ptr;
  4581. X
  4582. X      if (f_multivol)
  4583. X        {
  4584. X          ptr = malloc (strlen (f_volhdr) + 20);
  4585. X          sprintf (ptr, "%s Volume %d", f_volhdr, 1);
  4586. X        }
  4587. X      else
  4588. X        ptr = f_volhdr;
  4589. X#endif
  4590. X      head = findrec ();
  4591. X      if (!head)
  4592. X        {
  4593. X          msg ("Archive not labelled to match %s", f_volhdr);
  4594. X          exit (EX_BADVOL);
  4595. X        }
  4596. X      if (re_match (label_pattern, head->header.arch_name,
  4597. X            strlen (head->header.arch_name), 0, 0) < 0)
  4598. X        {
  4599. X          msg ("Volume mismatch!  %s!=%s", f_volhdr,
  4600. X           head->header.arch_name);
  4601. X          exit (EX_BADVOL);
  4602. X        }
  4603. X#if 0
  4604. X      if (strcmp (ptr, head->header.name))
  4605. X        {
  4606. X          msg ("Volume mismatch!  %s!=%s", ptr, head->header.name);
  4607. X          exit (EX_BADVOL);
  4608. X        }
  4609. X      if (ptr != f_volhdr)
  4610. X        free (ptr);
  4611. X#endif
  4612. X    }
  4613. X    }
  4614. X  else if (f_volhdr)
  4615. X    {
  4616. X      bzero ((void *) ar_block, RECORDSIZE);
  4617. X      if (f_multivol)
  4618. X    sprintf (ar_block->header.arch_name, "%s Volume 1", f_volhdr);
  4619. X      else
  4620. X    strcpy (ar_block->header.arch_name, f_volhdr);
  4621. X      current_file_name = ar_block->header.arch_name;
  4622. X      ar_block->header.linkflag = LF_VOLHDR;
  4623. X      to_oct (time (0), 1 + 12, ar_block->header.mtime);
  4624. X      finish_header (ar_block);
  4625. X      /* ar_record++; */
  4626. X    }
  4627. X}
  4628. X
  4629. X
  4630. X/*
  4631. X * Remember a union record * as pointing to something that we
  4632. X * need to keep when reading onward in the file.  Only one such
  4633. X * thing can be remembered at once, and it only works when reading
  4634. X * an archive.
  4635. X *
  4636. X * We calculate "offset" then add it because some compilers end up
  4637. X * adding (baserec+ar_record), doing a 9-bit shift of baserec, then
  4638. X * subtracting ar_block from that, shifting it back, losing the top 9 bits.
  4639. X */
  4640. Xvoid
  4641. Xsaverec (pointer)
  4642. X     union record **pointer;
  4643. X{
  4644. X  long offset;
  4645. X
  4646. X  save_rec = pointer;
  4647. X  offset = ar_record - ar_block;
  4648. X  saved_recno = baserec + offset;
  4649. X}
  4650. X
  4651. X/*
  4652. X * Perform a write to flush the buffer.
  4653. X */
  4654. X
  4655. X/*send_buffer_to_file();
  4656. X  if(new_volume) {
  4657. X      deal_with_new_volume_stuff();
  4658. X    send_buffer_to_file();
  4659. X  }
  4660. X */
  4661. X
  4662. Xvoid
  4663. Xfl_write ()
  4664. X{
  4665. X  int err;
  4666. X  int copy_back;
  4667. X  static long bytes_written = 0;
  4668. X
  4669. X  if (f_checkpoint && !(++checkpoint % 10))
  4670. X    msg ("Write checkpoint %d\n", checkpoint);
  4671. X  if (tape_length && bytes_written >= tape_length * 1024)
  4672. X    {
  4673. X      errno = ENOSPC;
  4674. X      err = 0;
  4675. X    }
  4676. X  else
  4677. X    err = rmtwrite (archive, ar_block->charptr, (int) blocksize);
  4678. X  if (err != blocksize && !f_multivol)
  4679. X    writeerror (err);
  4680. X  else if (f_totals)
  4681. X    tot_written += blocksize;
  4682. X
  4683. X  if (err > 0)
  4684. X    bytes_written += err;
  4685. X  if (err == blocksize)
  4686. X    {
  4687. X      if (f_multivol)
  4688. X    {
  4689. X      if (!save_name)
  4690. X        {
  4691. X          real_s_name[0] = '\0';
  4692. X          real_s_totsize = 0;
  4693. X          real_s_sizeleft = 0;
  4694. X          return;
  4695. X        }
  4696. X#ifdef __MSDOS__
  4697. X      if (save_name[1] == ':')
  4698. X        save_name += 2;
  4699. X#endif
  4700. X      while (*save_name == '/')
  4701. X        save_name++;
  4702. X
  4703. X      strcpy (real_s_name, save_name);
  4704. X      real_s_totsize = save_totsize;
  4705. X      real_s_sizeleft = save_sizeleft;
  4706. X    }
  4707. X      return;
  4708. X    }
  4709. X
  4710. X  /* We're multivol  Panic if we didn't get the right kind of response */
  4711. X  /* ENXIO is for the UNIX PC */
  4712. X  if (err < 0 && errno != ENOSPC && errno != EIO && errno != ENXIO)
  4713. X    writeerror (err);
  4714. X
  4715. X  /* If error indicates a short write, we just move to the next tape. */
  4716. X
  4717. X  if (new_volume (0) < 0)
  4718. X    return;
  4719. X  bytes_written = 0;
  4720. X  if (f_volhdr && real_s_name[0])
  4721. X    {
  4722. X      copy_back = 2;
  4723. X      ar_block -= 2;
  4724. X    }
  4725. X  else if (f_volhdr || real_s_name[0])
  4726. X    {
  4727. X      copy_back = 1;
  4728. X      ar_block--;
  4729. X    }
  4730. X  else
  4731. X    copy_back = 0;
  4732. X  if (f_volhdr)
  4733. X    {
  4734. X      bzero ((void *) ar_block, RECORDSIZE);
  4735. X      sprintf (ar_block->header.arch_name, "%s Volume %d", f_volhdr, volno);
  4736. X      to_oct (time (0), 1 + 12, ar_block->header.mtime);
  4737. X      ar_block->header.linkflag = LF_VOLHDR;
  4738. X      finish_header (ar_block);
  4739. X    }
  4740. X  if (real_s_name[0])
  4741. X    {
  4742. X      int tmp;
  4743. X
  4744. X      if (f_volhdr)
  4745. X    ar_block++;
  4746. X      bzero ((void *) ar_block, RECORDSIZE);
  4747. X      strcpy (ar_block->header.arch_name, real_s_name);
  4748. X      ar_block->header.linkflag = LF_MULTIVOL;
  4749. X      to_oct ((long) real_s_sizeleft, 1 + 12,
  4750. X          ar_block->header.size);
  4751. X      to_oct ((long) real_s_totsize - real_s_sizeleft,
  4752. X          1 + 12, ar_block->header.offset);
  4753. X      tmp = f_verbose;
  4754. X      f_verbose = 0;
  4755. X      finish_header (ar_block);
  4756. X      f_verbose = tmp;
  4757. X      if (f_volhdr)
  4758. X    ar_block--;
  4759. X    }
  4760. X
  4761. X  err = rmtwrite (archive, ar_block->charptr, (int) blocksize);
  4762. X  if (err != blocksize)
  4763. X    writeerror (err);
  4764. X  else if (f_totals)
  4765. X    tot_written += blocksize;
  4766. X
  4767. X
  4768. X  bytes_written = blocksize;
  4769. X  if (copy_back)
  4770. X    {
  4771. X      ar_block += copy_back;
  4772. X      bcopy ((void *) (ar_block + blocking - copy_back),
  4773. X         (void *) ar_record,
  4774. X         copy_back * RECORDSIZE);
  4775. X      ar_record += copy_back;
  4776. X
  4777. X      if (real_s_sizeleft >= copy_back * RECORDSIZE)
  4778. X    real_s_sizeleft -= copy_back * RECORDSIZE;
  4779. X      else if ((real_s_sizeleft + RECORDSIZE - 1) / RECORDSIZE <= copy_back)
  4780. X    real_s_name[0] = '\0';
  4781. X      else
  4782. X    {
  4783. X#ifdef __MSDOS__
  4784. X      if (save_name[1] == ':')
  4785. X        save_name += 2;
  4786. X#endif
  4787. X      while (*save_name == '/')
  4788. X        save_name++;
  4789. X
  4790. X      strcpy (real_s_name, save_name);
  4791. X      real_s_sizeleft = save_sizeleft;
  4792. X      real_s_totsize = save_totsize;
  4793. X    }
  4794. X      copy_back = 0;
  4795. X    }
  4796. X}
  4797. X
  4798. X/* Handle write errors on the archive.  Write errors are always fatal */
  4799. X/* Hitting the end of a volume does not cause a write error unless the write
  4800. X*  was the first block of the volume */
  4801. X
  4802. Xvoid
  4803. Xwriteerror (err)
  4804. X     int err;
  4805. X{
  4806. X  if (err < 0)
  4807. X    {
  4808. X      msg_perror ("can't write to %s", ar_files[cur_ar_file]);
  4809. X      exit (EX_BADARCH);
  4810. X    }
  4811. X  else
  4812. X    {
  4813. X      msg ("only wrote %u of %u bytes to %s", err, blocksize, ar_files[cur_ar_file]);
  4814. X      exit (EX_BADARCH);
  4815. X    }
  4816. X}
  4817. X
  4818. X/*
  4819. X * Handle read errors on the archive.
  4820. X *
  4821. X * If the read should be retried, readerror() returns to the caller.
  4822. X */
  4823. Xvoid
  4824. Xreaderror ()
  4825. X{
  4826. X#    define    READ_ERROR_MAX    10
  4827. X
  4828. X  read_error_flag++;        /* Tell callers */
  4829. X
  4830. X  msg_perror ("read error on %s", ar_files[cur_ar_file]);
  4831. X
  4832. X  if (baserec == 0)
  4833. X    {
  4834. X      /* First block of tape.  Probably stupidity error */
  4835. X      exit (EX_BADARCH);
  4836. X    }
  4837. X
  4838. X  /*
  4839. X     * Read error in mid archive.  We retry up to READ_ERROR_MAX times
  4840. X     * and then give up on reading the archive.  We set read_error_flag
  4841. X     * for our callers, so they can cope if they want.
  4842. X     */
  4843. X  if (r_error_count++ > READ_ERROR_MAX)
  4844. X    {
  4845. X      msg ("Too many errors, quitting.");
  4846. X      exit (EX_BADARCH);
  4847. X    }
  4848. X  return;
  4849. X}
  4850. X
  4851. X
  4852. X/*
  4853. X * Perform a read to flush the buffer.
  4854. X */
  4855. Xvoid
  4856. Xfl_read ()
  4857. X{
  4858. X  int err;            /* Result from system call */
  4859. X  int left;            /* Bytes left */
  4860. X  char *more;            /* Pointer to next byte to read */
  4861. X
  4862. X  if (f_checkpoint && !(++checkpoint % 10))
  4863. X    msg ("Read checkpoint %d\n", checkpoint);
  4864. X
  4865. X  /*
  4866. X     * Clear the count of errors.  This only applies to a single
  4867. X     * call to fl_read.  We leave read_error_flag alone; it is
  4868. X     * only turned off by higher level software.
  4869. X     */
  4870. X  r_error_count = 0;        /* Clear error count */
  4871. X
  4872. X  /*
  4873. X     * If we are about to wipe out a record that
  4874. X     * somebody needs to keep, copy it out to a holding
  4875. X     * area and adjust somebody's pointer to it.
  4876. X     */
  4877. X  if (save_rec &&
  4878. X      *save_rec >= ar_record &&
  4879. X      *save_rec < ar_last)
  4880. X    {
  4881. X      record_save_area = **save_rec;
  4882. X      *save_rec = &record_save_area;
  4883. X    }
  4884. X  if (write_archive_to_stdout && baserec != 0)
  4885. X    {
  4886. X      err = rmtwrite (1, ar_block->charptr, blocksize);
  4887. X      if (err != blocksize)
  4888. X    writeerror (err);
  4889. X    }
  4890. X  if (f_multivol)
  4891. X    {
  4892. X      if (save_name)
  4893. X    {
  4894. X      if (save_name != real_s_name)
  4895. X        {
  4896. X#ifdef __MSDOS__
  4897. X          if (save_name[1] == ':')
  4898. X        save_name += 2;
  4899. X#endif
  4900. X          while (*save_name == '/')
  4901. X        save_name++;
  4902. X
  4903. X          strcpy (real_s_name, save_name);
  4904. X          save_name = real_s_name;
  4905. X        }
  4906. X      real_s_totsize = save_totsize;
  4907. X      real_s_sizeleft = save_sizeleft;
  4908. X
  4909. X    }
  4910. X      else
  4911. X    {
  4912. X      real_s_name[0] = '\0';
  4913. X      real_s_totsize = 0;
  4914. X      real_s_sizeleft = 0;
  4915. X    }
  4916. X    }
  4917. X
  4918. Xerror_loop:
  4919. X  err = rmtread (archive, ar_block->charptr, (int) blocksize);
  4920. X  if (err == blocksize)
  4921. X    return;
  4922. X
  4923. X  if ((err == 0 || (err < 0 && errno == ENOSPC) || (err > 0 && !f_reblock)) && f_multivol)
  4924. X    {
  4925. X      union record *head;
  4926. X
  4927. X    try_volume:
  4928. X      if (new_volume ((cmd_mode == CMD_APPEND || cmd_mode == CMD_CAT || cmd_mode == CMD_UPDATE) ? 2 : 1) < 0)
  4929. X    return;
  4930. X    vol_error:
  4931. X      err = rmtread (archive, ar_block->charptr, (int) blocksize);
  4932. X      if (err < 0)
  4933. X    {
  4934. X      readerror ();
  4935. X      goto vol_error;
  4936. X    }
  4937. X      if (err != blocksize)
  4938. X    goto short_read;
  4939. X
  4940. X      head = ar_block;
  4941. X
  4942. X      if (head->header.linkflag == LF_VOLHDR)
  4943. X    {
  4944. X      if (f_volhdr)
  4945. X        {
  4946. X#if 0
  4947. X          char *ptr;
  4948. X
  4949. X          ptr = (char *) malloc (strlen (f_volhdr) + 20);
  4950. X          sprintf (ptr, "%s Volume %d", f_volhdr, volno);
  4951. X#endif
  4952. X          if (re_match (label_pattern, head->header.arch_name,
  4953. X                strlen (head->header.arch_name),
  4954. X                0, 0) < 0)
  4955. X        {
  4956. X          msg ("Volume mismatch! %s!=%s", f_volhdr,
  4957. X               head->header.arch_name);
  4958. X          --volno;
  4959. X          --global_volno;
  4960. X          goto try_volume;
  4961. X        }
  4962. X
  4963. X#if 0
  4964. X          if (strcmp (ptr, head->header.name))
  4965. X        {
  4966. X          msg ("Volume mismatch! %s!=%s", ptr, head->header.name);
  4967. X          --volno;
  4968. X          --global_volno;
  4969. X          free (ptr);
  4970. X          goto try_volume;
  4971. X        }
  4972. X          free (ptr);
  4973. X#endif
  4974. X        }
  4975. X      if (f_verbose)
  4976. X        fprintf (msg_file, "Reading %s\n", head->header.arch_name);
  4977. X      head++;
  4978. X    }
  4979. X      else if (f_volhdr)
  4980. X    {
  4981. X      msg ("Warning:  No volume header!");
  4982. X    }
  4983. X
  4984. X      if (real_s_name[0])
  4985. X    {
  4986. X      long from_oct ();
  4987. X
  4988. X      if (head->header.linkflag != LF_MULTIVOL || strcmp (head->header.arch_name, real_s_name))
  4989. X        {
  4990. X          msg ("%s is not continued on this volume!", real_s_name);
  4991. X          --volno;
  4992. X          --global_volno;
  4993. X          goto try_volume;
  4994. X        }
  4995. X      if (real_s_totsize != from_oct (1 + 12, head->header.size) + from_oct (1 + 12, head->header.offset))
  4996. X        {
  4997. X          msg ("%s is the wrong size (%ld!=%ld+%ld)",
  4998. X           head->header.arch_name, save_totsize,
  4999. X           from_oct (1 + 12, head->header.size),
  5000. X           from_oct (1 + 12, head->header.offset));
  5001. X          --volno;
  5002. X          --global_volno;
  5003. X          goto try_volume;
  5004. X        }
  5005. X      if (real_s_totsize - real_s_sizeleft != from_oct (1 + 12, head->header.offset))
  5006. X        {
  5007. X          msg ("This volume is out of sequence");
  5008. X          --volno;
  5009. X          --global_volno;
  5010. X          goto try_volume;
  5011. X        }
  5012. X      head++;
  5013. X    }
  5014. X      ar_record = head;
  5015. X      return;
  5016. X    }
  5017. X  else if (err < 0)
  5018. X    {
  5019. X      readerror ();
  5020. X      goto error_loop;        /* Try again */
  5021. X    }
  5022. X
  5023. Xshort_read:
  5024. X  more = ar_block->charptr + err;
  5025. X  left = blocksize - err;
  5026. X
  5027. Xagain:
  5028. X  if (0 == (((unsigned) left) % RECORDSIZE))
  5029. X    {
  5030. X      /* FIXME, for size=0, multi vol support */
  5031. X      /* On the first block, warn about the problem */
  5032. X      if (!f_reblock && baserec == 0 && f_verbose && err > 0)
  5033. X    {
  5034. X      /*    msg("Blocksize = %d record%s",
  5035. X                err / RECORDSIZE, (err > RECORDSIZE)? "s": "");*/
  5036. X      msg ("Blocksize = %d records", err / RECORDSIZE);
  5037. X    }
  5038. X      ar_last = ar_block + ((unsigned) (blocksize - left)) / RECORDSIZE;
  5039. X      return;
  5040. X    }
  5041. X  if (f_reblock)
  5042. X    {
  5043. X      /*
  5044. X         * User warned us about this.  Fix up.
  5045. X         */
  5046. X      if (left > 0)
  5047. X    {
  5048. X    error2loop:
  5049. X      err = rmtread (archive, more, (int) left);
  5050. X      if (err < 0)
  5051. X        {
  5052. X          readerror ();
  5053. X          goto error2loop;    /* Try again */
  5054. X        }
  5055. X      if (err == 0)
  5056. X        {
  5057. X          msg ("archive %s EOF not on block boundary", ar_files[cur_ar_file]);
  5058. X          exit (EX_BADARCH);
  5059. X        }
  5060. X      left -= err;
  5061. X      more += err;
  5062. X      goto again;
  5063. X    }
  5064. X    }
  5065. X  else
  5066. X    {
  5067. X      msg ("only read %d bytes from archive %s", err, ar_files[cur_ar_file]);
  5068. X      exit (EX_BADARCH);
  5069. X    }
  5070. X}
  5071. X
  5072. X
  5073. X/*
  5074. X * Flush the current buffer to/from the archive.
  5075. X */
  5076. Xvoid
  5077. Xflush_archive ()
  5078. X{
  5079. X  int c;
  5080. X
  5081. X  baserec += ar_last - ar_block;/* Keep track of block #s */
  5082. X  ar_record = ar_block;        /* Restore pointer to start */
  5083. X  ar_last = ar_block + blocking;/* Restore pointer to end */
  5084. X
  5085. X  if (ar_reading)
  5086. X    {
  5087. X      if (time_to_start_writing)
  5088. X    {
  5089. X      time_to_start_writing = 0;
  5090. X      ar_reading = 0;
  5091. X
  5092. X      if (file_to_switch_to >= 0)
  5093. X        {
  5094. X          if ((c = rmtclose (archive)) < 0)
  5095. X        msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c);
  5096. X
  5097. X          archive = file_to_switch_to;
  5098. X        }
  5099. X      else
  5100. X        (void) backspace_output ();
  5101. X      fl_write ();
  5102. X    }
  5103. X      else
  5104. X    fl_read ();
  5105. X    }
  5106. X  else
  5107. X    {
  5108. X      fl_write ();
  5109. X    }
  5110. X}
  5111. X
  5112. X/* Backspace the archive descriptor by one blocks worth.
  5113. X   If its a tape, MTIOCTOP will work.  If its something else,
  5114. X   we try to seek on it.  If we can't seek, we lose! */
  5115. Xint
  5116. Xbackspace_output ()
  5117. X{
  5118. X  long cur;
  5119. X  /* int er; */
  5120. X  extern char *output_start;
  5121. X
  5122. X#ifdef MTIOCTOP
  5123. X  struct mtop t;
  5124. X
  5125. X  t.mt_op = MTBSR;
  5126. X  t.mt_count = 1;
  5127. X  if ((rmtioctl (archive, MTIOCTOP, &t)) >= 0)
  5128. X    return 1;
  5129. X  if (errno == EIO && (rmtioctl (archive, MTIOCTOP, &t)) >= 0)
  5130. X    return 1;
  5131. X#endif
  5132. X
  5133. X  cur = rmtlseek (archive, 0L, 1);
  5134. X  cur -= blocksize;
  5135. X  /* Seek back to the beginning of this block and
  5136. X       start writing there. */
  5137. X
  5138. X  if (rmtlseek (archive, cur, 0) != cur)
  5139. X    {
  5140. X      /* Lseek failed.  Try a different method */
  5141. X      msg ("Couldn't backspace archive file.  It may be unreadable without -i.");
  5142. X      /* Replace the first part of the block with nulls */
  5143. X      if (ar_block->charptr != output_start)
  5144. X    bzero (ar_block->charptr, output_start - ar_block->charptr);
  5145. X      return 2;
  5146. X    }
  5147. X  return 3;
  5148. X}
  5149. X
  5150. X
  5151. X/*
  5152. X * Close the archive file.
  5153. X */
  5154. Xvoid
  5155. Xclose_archive ()
  5156. X{
  5157. X  int child;
  5158. X  int status;
  5159. X  int c;
  5160. X
  5161. X  if (time_to_start_writing || !ar_reading)
  5162. X    flush_archive ();
  5163. X  if (cmd_mode == CMD_DELETE)
  5164. X    {
  5165. X      off_t pos;
  5166. X
  5167. X      pos = rmtlseek (archive, 0L, 1);
  5168. X#ifndef __MSDOS__
  5169. X      (void) ftruncate (archive, pos);
  5170. X#else
  5171. X      (void) rmtwrite (archive, "", 0);
  5172. X#endif
  5173. X    }
  5174. X  if (f_verify)
  5175. X    verify_volume ();
  5176. X
  5177. X  if ((c = rmtclose (archive)) < 0)
  5178. X    msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c);
  5179. X
  5180. X#ifndef    __MSDOS__
  5181. X  if (childpid)
  5182. X    {
  5183. X      /*
  5184. X       * Loop waiting for the right child to die, or for
  5185. X       * no more kids.
  5186. X       */
  5187. X      while (((child = wait (&status)) != childpid) && child != -1)
  5188. X    ;
  5189. X
  5190. X      if (child != -1)
  5191. X    {
  5192. X      if (WIFSIGNALED (status))
  5193. X        {
  5194. X          /* SIGPIPE is OK, everything else is a problem. */
  5195. X          if (WTERMSIG (status) != SIGPIPE)
  5196. X        msg ("child died with signal %d%s", WTERMSIG (status),
  5197. X             WIFCOREDUMPED (status) ? " (core dumped)" : "");
  5198. X        }
  5199. X      else
  5200. X        {
  5201. X          /* Child voluntarily terminated  -- but why? */
  5202. X          if (WEXITSTATUS (status) == MAGIC_STAT)
  5203. X        {
  5204. X          exit (EX_SYSTEM);    /* Child had trouble */
  5205. X        }
  5206. X          if (WEXITSTATUS (status) == (SIGPIPE + 128))
  5207. X        {
  5208. X          /*
  5209. X           * /bin/sh returns this if its child
  5210. X           * dies with SIGPIPE.  'Sok.
  5211. X           */
  5212. X          /* Do nothing. */
  5213. X        }
  5214. X          else if (WEXITSTATUS (status))
  5215. X        msg ("child returned status %d",
  5216. X             WEXITSTATUS (status));
  5217. X        }
  5218. X    }
  5219. X    }
  5220. X#endif /* __MSDOS__ */
  5221. X}
  5222. X
  5223. X
  5224. X#ifdef DONTDEF
  5225. X/*
  5226. X * Message management.
  5227. X *
  5228. X * anno writes a message prefix on stream (eg stdout, stderr).
  5229. X *
  5230. X * The specified prefix is normally output followed by a colon and a space.
  5231. X * However, if other command line options are set, more output can come
  5232. X * out, such as the record # within the archive.
  5233. X *
  5234. X * If the specified prefix is NULL, no output is produced unless the
  5235. X * command line option(s) are set.
  5236. X *
  5237. X * If the third argument is 1, the "saved" record # is used; if 0, the
  5238. X * "current" record # is used.
  5239. X */
  5240. Xvoid
  5241. Xanno (stream, prefix, savedp)
  5242. X     FILE *stream;
  5243. X     char *prefix;
  5244. X     int savedp;
  5245. X{
  5246. X#    define    MAXANNO    50
  5247. X  char buffer[MAXANNO];        /* Holds annorecment */
  5248. X#    define    ANNOWIDTH 13
  5249. X  int space;
  5250. X  long offset;
  5251. X  int save_e;
  5252. X
  5253. X  save_e = errno;
  5254. X  /* Make sure previous output gets out in sequence */
  5255. X  if (stream == stderr)
  5256. X    fflush (stdout);
  5257. X  if (f_sayblock)
  5258. X    {
  5259. X      if (prefix)
  5260. X    {
  5261. X      fputs (prefix, stream);
  5262. X      putc (' ', stream);
  5263. X    }
  5264. X      offset = ar_record - ar_block;
  5265. X      (void) sprintf (buffer, "rec %d: ",
  5266. X              savedp ? saved_recno :
  5267. X              baserec + offset);
  5268. X      fputs (buffer, stream);
  5269. X      space = ANNOWIDTH - strlen (buffer);
  5270. X      if (space > 0)
  5271. X    {
  5272. X      fprintf (stream, "%*s", space, "");
  5273. X    }
  5274. X    }
  5275. X  else if (prefix)
  5276. X    {
  5277. X      fputs (prefix, stream);
  5278. X      fputs (": ", stream);
  5279. X    }
  5280. X  errno = save_e;
  5281. X}
  5282. X
  5283. X#endif
  5284. X
  5285. X/* Called to initialize the global volume number. */
  5286. Xvoid
  5287. Xinit_volume_number ()
  5288. X{
  5289. X  FILE *vf;
  5290. X
  5291. X  vf = fopen (f_volno_file, "r");
  5292. X  if (!vf && errno != ENOENT)
  5293. X    msg_perror ("%s", f_volno_file);
  5294. X
  5295. X  if (vf)
  5296. X    {
  5297. X      fscanf (vf, "%d", &global_volno);
  5298. X      fclose (vf);
  5299. X    }
  5300. X}
  5301. X
  5302. X/* Called to write out the closing global volume number. */
  5303. Xvoid
  5304. Xcloseout_volume_number ()
  5305. X{
  5306. X  FILE *vf;
  5307. X
  5308. X  vf = fopen (f_volno_file, "w");
  5309. X  if (!vf)
  5310. X    msg_perror ("%s", f_volno_file);
  5311. X  else
  5312. X    {
  5313. X      fprintf (vf, "%d\n", global_volno);
  5314. X      fclose (vf);
  5315. X    }
  5316. X}
  5317. X
  5318. X/* We've hit the end of the old volume.  Close it and open the next one */
  5319. X/* Values for type:  0: writing  1: reading  2: updating */
  5320. Xint
  5321. Xnew_volume (type)
  5322. X     int type;
  5323. X{
  5324. X  int c;
  5325. X  char inbuf[80];
  5326. X  char *p;
  5327. X  static FILE *read_file = 0;
  5328. X  extern int now_verifying;
  5329. X  extern char TTY_NAME[];
  5330. X  static int looped = 0;
  5331. X
  5332. X  if (!read_file && !f_run_script_at_end)
  5333. X    read_file = (archive == 0) ? fopen (TTY_NAME, "r") : stdin;
  5334. X
  5335. X  if (now_verifying)
  5336. X    return -1;
  5337. X  if (f_verify)
  5338. X    verify_volume ();
  5339. X  if ((c = rmtclose (archive)) < 0)
  5340. X    msg_perror ("Warning: can't close %s(%d,%d)", ar_files[cur_ar_file], archive, c);
  5341. X
  5342. X  global_volno++;
  5343. X  volno++;
  5344. X  cur_ar_file++;
  5345. X  if (cur_ar_file == n_ar_files)
  5346. X    {
  5347. X      cur_ar_file = 0;
  5348. X      looped = 1;
  5349. X    }
  5350. X
  5351. Xtryagain:
  5352. X  if (looped)
  5353. X    {
  5354. X      /* We have to prompt from now on. */
  5355. X      if (f_run_script_at_end)
  5356. X    {
  5357. X      closeout_volume_number ();
  5358. X      system (info_script);
  5359. X    }
  5360. X      else
  5361. X    for (;;)
  5362. X      {
  5363. X        fprintf (msg_file, "\007Prepare volume #%d for %s and hit return: ", global_volno, ar_files[cur_ar_file]);
  5364. X        fflush (msg_file);
  5365. X        if (fgets (inbuf, sizeof (inbuf), read_file) == 0)
  5366. X          {
  5367. X        fprintf (msg_file, "EOF?  What does that mean?");
  5368. X        if (cmd_mode != CMD_EXTRACT && cmd_mode != CMD_LIST && cmd_mode != CMD_DIFF)
  5369. X          msg ("Warning:  Archive is INCOMPLETE!");
  5370. X        exit (EX_BADARCH);
  5371. X          }
  5372. X        if (inbuf[0] == '\n' || inbuf[0] == 'y' || inbuf[0] == 'Y')
  5373. X          break;
  5374. X
  5375. X        switch (inbuf[0])
  5376. X          {
  5377. X          case '?':
  5378. X        {
  5379. X          fprintf (msg_file, "\
  5380. X n [name]   Give a new filename for the next (and subsequent) volume(s)\n\
  5381. X q          Abort tar\n\
  5382. X !          Spawn a subshell\n\
  5383. X ?          Print this list\n");
  5384. X        }
  5385. X        break;
  5386. X
  5387. X          case 'q':    /* Quit */
  5388. X        fprintf (msg_file, "No new volume; exiting.\n");
  5389. X        if (cmd_mode != CMD_EXTRACT && cmd_mode != CMD_LIST && cmd_mode != CMD_DIFF)
  5390. X          msg ("Warning:  Archive is INCOMPLETE!");
  5391. X        exit (EX_BADARCH);
  5392. X
  5393. X          case 'n':    /* Get new file name */
  5394. X        {
  5395. X          char *q, *r;
  5396. X          static char *old_name;
  5397. X
  5398. X          for (q = &inbuf[1]; *q == ' ' || *q == '\t'; q++)
  5399. X            ;
  5400. X          for (r = q; *r; r++)
  5401. X            if (*r == '\n')
  5402. X              *r = '\0';
  5403. X          old_name = p = (char *) malloc ((unsigned) (strlen (q) + 2));
  5404. X          if (p == 0)
  5405. X            {
  5406. X              msg ("Can't allocate memory for name");
  5407. X              exit (EX_SYSTEM);
  5408. X            }
  5409. X          (void) strcpy (p, q);
  5410. X          ar_files[cur_ar_file] = p;
  5411. X        }
  5412. X        break;
  5413. X
  5414. X          case '!':
  5415. X#ifdef __MSDOS__
  5416. X        spawnl (P_WAIT, getenv ("COMSPEC"), "-", 0);
  5417. X#else
  5418. X        /* JF this needs work! */
  5419. X        switch (fork ())
  5420. X          {
  5421. X          case -1:
  5422. X            msg_perror ("can't fork!");
  5423. X            break;
  5424. X          case 0:
  5425. X            p = getenv ("SHELL");
  5426. X            if (p == 0)
  5427. X              p = "/bin/sh";
  5428. X            execlp (p, "-sh", "-i", 0);
  5429. X            msg_perror ("can't exec a shell %s", p);
  5430. X            _exit (55);
  5431. X          default:
  5432. X            wait (0);
  5433. X            break;
  5434. X          }
  5435. X#endif
  5436. X        break;
  5437. X          }
  5438. X      }
  5439. X    }
  5440. X
  5441. X
  5442. X  if (type == 2 || f_verify)
  5443. X    archive = rmtopen (ar_files[cur_ar_file], O_RDWR | O_CREAT, 0666);
  5444. X  else if (type == 1)
  5445. X    archive = rmtopen (ar_files[cur_ar_file], O_RDONLY, 0666);
  5446. X  else if (type == 0)
  5447. X    archive = rmtcreat (ar_files[cur_ar_file], 0666);
  5448. X  else
  5449. X    archive = -1;
  5450. X
  5451. X  if (archive < 0)
  5452. X    {
  5453. X      msg_perror ("can't open %s", ar_files[cur_ar_file]);
  5454. X      goto tryagain;
  5455. X    }
  5456. X#ifdef __MSDOS__
  5457. X  setmode (archive, O_BINARY);
  5458. X#endif
  5459. X  return 0;
  5460. X}
  5461. X
  5462. X/* this is a useless function that takes a buffer returned by wantbytes
  5463. X   and does nothing with it.  If the function called by wantbytes returns
  5464. X   an error indicator (non-zero), this function is called for the rest of
  5465. X   the file.
  5466. X */
  5467. Xint
  5468. Xno_op (size, data)
  5469. X     int size;
  5470. X     char *data;
  5471. X{
  5472. X  return 0;
  5473. X}
  5474. X
  5475. X/* Some other routine wants SIZE bytes in the archive.  For each chunk of
  5476. X   the archive, call FUNC with the size of the chunk, and the address of
  5477. X   the chunk it can work with.
  5478. X */
  5479. Xint
  5480. Xwantbytes (size, func)
  5481. X     long size;
  5482. X     int (*func) ();
  5483. X{
  5484. X  char *data;
  5485. X  long data_size;
  5486. X
  5487. X  while (size)
  5488. X    {
  5489. X      data = findrec ()->charptr;
  5490. X      if (data == NULL)
  5491. X    {            /* Check it... */
  5492. X      msg ("Unexpected EOF on archive file");
  5493. X      return -1;
  5494. X    }
  5495. X      data_size = endofrecs ()->charptr - data;
  5496. X      if (data_size > size)
  5497. X    data_size = size;
  5498. X      if ((*func) (data_size, data))
  5499. X    func = no_op;
  5500. X      userec ((union record *) (data + data_size - 1));
  5501. X      size -= data_size;
  5502. X    }
  5503. X  return 0;
  5504. X}
  5505. END_OF_FILE
  5506. if test 35194 -ne `wc -c <'buffer.c'`; then
  5507.     echo shar: \"'buffer.c'\" unpacked with wrong size!
  5508. fi
  5509. # end of 'buffer.c'
  5510. fi
  5511. if test -f 'getoldopt.c' -a "${1}" != "-c" ; then 
  5512.   echo shar: Will not clobber existing file \"'getoldopt.c'\"
  5513. else
  5514. echo shar: Extracting \"'getoldopt.c'\" \(2310 characters\)
  5515. sed "s/^X//" >'getoldopt.c' <<'END_OF_FILE'
  5516. X/* Replacement for getopt() that can be used by tar.
  5517. X   Copyright (C) 1988 Free Software Foundation
  5518. X
  5519. XThis file is part of GNU Tar.
  5520. X
  5521. XGNU Tar is free software; you can redistribute it and/or modify
  5522. Xit under the terms of the GNU General Public License as published by
  5523. Xthe Free Software Foundation; either version 2, or (at your option)
  5524. Xany later version.
  5525. X
  5526. XGNU Tar is distributed in the hope that it will be useful,
  5527. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  5528. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  5529. XGNU General Public License for more details.
  5530. X
  5531. XYou should have received a copy of the GNU General Public License
  5532. Xalong with GNU Tar; see the file COPYING.  If not, write to
  5533. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  5534. X
  5535. X/*
  5536. X * Plug-compatible replacement for getopt() for parsing tar-like
  5537. X * arguments.  If the first argument begins with "-", it uses getopt;
  5538. X * otherwise, it uses the old rules used by tar, dump, and ps.
  5539. X *
  5540. X * Written 25 August 1985 by John Gilmore (ihnp4!hoptoad!gnu)
  5541. X */
  5542. X
  5543. X#include <stdio.h>
  5544. X#include "getopt.h"
  5545. X#include "tar.h"        /* For msg() declaration if STDC_MSG. */
  5546. X#include <sys/types.h>
  5547. X#include "port.h"
  5548. X
  5549. Xint
  5550. Xgetoldopt (argc, argv, optstring, long_options, opt_index)
  5551. X     int argc;
  5552. X     char **argv;
  5553. X     char *optstring;
  5554. X     struct option *long_options;
  5555. X     int *opt_index;
  5556. X{
  5557. X  extern char *optarg;        /* Points to next arg */
  5558. X  extern int optind;        /* Global argv index */
  5559. X  static char *key;        /* Points to next keyletter */
  5560. X  static char use_getopt;    /* !=0 if argv[1][0] was '-' */
  5561. X  char c;
  5562. X  char *place;
  5563. X
  5564. X  optarg = NULL;
  5565. X
  5566. X  if (key == NULL)
  5567. X    {                /* First time */
  5568. X      if (argc < 2)
  5569. X    return EOF;
  5570. X      key = argv[1];
  5571. X      if ((*key == '-') || (*key == '+'))
  5572. X    use_getopt++;
  5573. X      else
  5574. X    optind = 2;
  5575. X    }
  5576. X
  5577. X  if (use_getopt)
  5578. X    return getopt_long (argc, argv, optstring,
  5579. X            long_options, opt_index);
  5580. X
  5581. X  c = *key++;
  5582. X  if (c == '\0')
  5583. X    {
  5584. X      key--;
  5585. X      return EOF;
  5586. X    }
  5587. X  place = index (optstring, c);
  5588. X
  5589. X  if (place == NULL || c == ':')
  5590. X    {
  5591. X      msg ("unknown option %c", c);
  5592. X      return ('?');
  5593. X    }
  5594. X
  5595. X  place++;
  5596. X  if (*place == ':')
  5597. X    {
  5598. X      if (optind < argc)
  5599. X    {
  5600. X      optarg = argv[optind];
  5601. X      optind++;
  5602. X    }
  5603. X      else
  5604. X    {
  5605. X      msg ("%c argument missing", c);
  5606. X      return ('?');
  5607. X    }
  5608. X    }
  5609. X
  5610. X  return (c);
  5611. X}
  5612. END_OF_FILE
  5613. if test 2310 -ne `wc -c <'getoldopt.c'`; then
  5614.     echo shar: \"'getoldopt.c'\" unpacked with wrong size!
  5615. fi
  5616. # end of 'getoldopt.c'
  5617. fi
  5618. if test -f 'update.c' -a "${1}" != "-c" ; then 
  5619.   echo shar: Will not clobber existing file \"'update.c'\"
  5620. else
  5621. echo shar: Extracting \"'update.c'\" \(13900 characters\)
  5622. sed "s/^X//" >'update.c' <<'END_OF_FILE'
  5623. X/* Update a tar archive.
  5624. X   Copyright (C) 1988, 1992 Free Software Foundation
  5625. X
  5626. XThis file is part of GNU Tar.
  5627. X
  5628. XGNU Tar is free software; you can redistribute it and/or modify
  5629. Xit under the terms of the GNU General Public License as published by
  5630. Xthe Free Software Foundation; either version 2, or (at your option)
  5631. Xany later version.
  5632. X
  5633. XGNU Tar is distributed in the hope that it will be useful,
  5634. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  5635. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  5636. XGNU General Public License for more details.
  5637. X
  5638. XYou should have received a copy of the GNU General Public License
  5639. Xalong with GNU Tar; see the file COPYING.  If not, write to
  5640. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  5641. X
  5642. X/* JF implement the 'r' 'u' and 'A' options for tar. */
  5643. X/* The 'A' option is my own invention:  It means that the file-names are
  5644. X   tar files, and they should simply be appended to the end of the archive.
  5645. X   No attempt is made to block the reads from the args; if they're on raw
  5646. X   tape or something like that, it'll probably lose. . . */
  5647. X
  5648. X#include <sys/types.h>
  5649. X#include <stdio.h>
  5650. X#include <errno.h>
  5651. X#ifndef STDC_HEADERS
  5652. Xextern int errno;
  5653. X#endif
  5654. X
  5655. X#ifdef HAVE_SYS_MTIO_H
  5656. X#include <sys/ioctl.h>
  5657. X#include <sys/mtio.h>
  5658. X#endif
  5659. X
  5660. X#ifdef BSD42
  5661. X#include <sys/file.h>
  5662. X#else
  5663. X#ifndef V7
  5664. X#include <fcntl.h>
  5665. X#endif
  5666. X#endif
  5667. X
  5668. X#ifndef    __MSDOS__
  5669. X#include <pwd.h>
  5670. X#include <grp.h>
  5671. X#endif
  5672. X
  5673. X#define STDIN 0
  5674. X#define STDOUT 1
  5675. X
  5676. X#include "tar.h"
  5677. X#include "port.h"
  5678. X#include "rmt.h"
  5679. X
  5680. Xint time_to_start_writing = 0;    /* We've hit the end of the old stuff,
  5681. X                   and its time to start writing new stuff
  5682. X                   to the tape.  This involves seeking
  5683. X                   back one block and re-writing the current
  5684. X                   block (which has been changed). */
  5685. X
  5686. Xchar *output_start;        /* Pointer to where we started to write in
  5687. X                   the first block we write out.  This is used
  5688. X                   if we can't backspace the output and have
  5689. X                   to null out the first part of the block */
  5690. X
  5691. Xextern void skip_file ();
  5692. Xextern void skip_extended_headers ();
  5693. X
  5694. Xextern union record *head;
  5695. Xextern struct stat hstat;
  5696. X
  5697. Xvoid append_file ();
  5698. Xvoid close_archive ();
  5699. Xint confirm ();
  5700. Xvoid decode_header ();
  5701. Xvoid fl_read ();
  5702. Xvoid fl_write ();
  5703. Xvoid flush_archive ();
  5704. Xint move_arch ();
  5705. Xstruct name *name_scan ();
  5706. Xchar *name_from_list ();
  5707. Xvoid name_expand ();
  5708. Xvoid name_gather ();
  5709. Xvoid names_notfound ();
  5710. Xvoid open_archive ();
  5711. Xint read_header ();
  5712. Xvoid reset_eof ();
  5713. Xvoid write_block ();
  5714. Xvoid write_eot ();
  5715. X
  5716. X/* Implement the 'r' (add files to end of archive), and 'u' (add files to
  5717. X   end of archive if they arent there, or are more up to date than the
  5718. X   version in the archive.) commands.*/
  5719. Xvoid
  5720. Xupdate_archive ()
  5721. X{
  5722. X  int found_end = 0;
  5723. X  int status = 3;
  5724. X  int prev_status;
  5725. X  char *p;
  5726. X  struct name *name;
  5727. X  extern void dump_file ();
  5728. X
  5729. X  name_gather ();
  5730. X  if (cmd_mode == CMD_UPDATE)
  5731. X    name_expand ();
  5732. X  open_archive (2);        /* Open for updating */
  5733. X
  5734. X  do
  5735. X    {
  5736. X      prev_status = status;
  5737. X      status = read_header ();
  5738. X      switch (status)
  5739. X    {
  5740. X    case EOF:
  5741. X      found_end = 1;
  5742. X      break;
  5743. X
  5744. X    case 0:        /* A bad record */
  5745. X      userec (head);
  5746. X      switch (prev_status)
  5747. X        {
  5748. X        case 3:
  5749. X          msg ("This doesn't look like a tar archive.");
  5750. X          /* FALL THROUGH */
  5751. X        case 2:
  5752. X        case 1:
  5753. X          msg ("Skipping to next header");
  5754. X        case 0:
  5755. X          break;
  5756. X        }
  5757. X      break;
  5758. X
  5759. X      /* A good record */
  5760. X    case 1:
  5761. X      /* printf("File %s\n",head->header.name); */
  5762. X      /* head->header.name[NAMSIZ-1]='\0'; */
  5763. X      if (cmd_mode == CMD_UPDATE && (name = name_scan (current_file_name)))
  5764. X        {
  5765. X
  5766. X          /* struct stat hstat; */
  5767. X          struct stat nstat;
  5768. X          int head_standard;
  5769. X
  5770. X          decode_header (head, &hstat, &head_standard, 0);
  5771. X          if (stat (current_file_name, &nstat) < 0)
  5772. X        {
  5773. X          msg_perror ("can't stat %s:", current_file_name);
  5774. X        }
  5775. X          else
  5776. X        {
  5777. X          if (hstat.st_mtime >= nstat.st_mtime)
  5778. X            name->found++;
  5779. X        }
  5780. X        }
  5781. X      userec (head);
  5782. X      if (head->header.isextended)
  5783. X        skip_extended_headers ();
  5784. X      skip_file ((long) hstat.st_size);
  5785. X      break;
  5786. X
  5787. X    case 2:
  5788. X      ar_record = head;
  5789. X      found_end = 1;
  5790. X      break;
  5791. X    }
  5792. X    }
  5793. X  while (!found_end);
  5794. X
  5795. X  reset_eof ();
  5796. X  time_to_start_writing = 1;
  5797. X  output_start = ar_record->charptr;
  5798. X
  5799. X  while (p = name_from_list ())
  5800. X    {
  5801. X      if (f_confirm && !confirm ("add", p))
  5802. X    continue;
  5803. X      if (cmd_mode == CMD_CAT)
  5804. X    append_file (p);
  5805. X      else
  5806. X    dump_file (p, -1, 1);
  5807. X    }
  5808. X
  5809. X  write_eot ();
  5810. X  close_archive ();
  5811. X  names_notfound ();
  5812. X}
  5813. X
  5814. X/* Catenate file p to the archive without creating a header for it.  It had
  5815. X   better be a tar file or the archive is screwed */
  5816. X
  5817. Xvoid
  5818. Xappend_file (p)
  5819. X     char *p;
  5820. X{
  5821. X  int fd;
  5822. X  struct stat statbuf;
  5823. X  long bytes_left;
  5824. X  union record *start;
  5825. X  long bufsiz, count;
  5826. X
  5827. X  if (0 != stat (p, &statbuf) || (fd = open (p, O_RDONLY | O_BINARY)) < 0)
  5828. X    {
  5829. X      msg_perror ("can't open file %s", p);
  5830. X      errors++;
  5831. X      return;
  5832. X    }
  5833. X
  5834. X  bytes_left = statbuf.st_size;
  5835. X
  5836. X  while (bytes_left > 0)
  5837. X    {
  5838. X      start = findrec ();
  5839. X      bufsiz = endofrecs ()->charptr - start->charptr;
  5840. X      if (bytes_left < bufsiz)
  5841. X    {
  5842. X      bufsiz = bytes_left;
  5843. X      count = bufsiz % RECORDSIZE;
  5844. X      if (count)
  5845. X        bzero (start->charptr + bytes_left, (int) (RECORDSIZE - count));
  5846. X    }
  5847. X      count = read (fd, start->charptr, bufsiz);
  5848. X      if (count < 0)
  5849. X    {
  5850. X      msg_perror ("read error at byte %ld reading %d bytes in file %s", statbuf.st_size - bytes_left, bufsiz, p);
  5851. X      exit (EX_ARGSBAD);    /* FOO */
  5852. X    }
  5853. X      bytes_left -= count;
  5854. X      userec (start + (count - 1) / RECORDSIZE);
  5855. X      if (count != bufsiz)
  5856. X    {
  5857. X      msg ("%s: file shrunk by %d bytes, yark!", p, bytes_left);
  5858. X      abort ();
  5859. X    }
  5860. X    }
  5861. X  (void) close (fd);
  5862. X}
  5863. X
  5864. X#ifdef DONTDEF
  5865. Xbprint (fp, buf, num)
  5866. X     FILE *fp;
  5867. X     char *buf;
  5868. X{
  5869. X  int c;
  5870. X
  5871. X  if (num == 0 || num == -1)
  5872. X    return;
  5873. X  fputs (" '", fp);
  5874. X  while (num--)
  5875. X    {
  5876. X      c = *buf++;
  5877. X      if (c == '\\')
  5878. X    fputs ("\\\\", fp);
  5879. X      else if (c >= ' ' && c <= '~')
  5880. X    putc (c, fp);
  5881. X      else
  5882. X    switch (c)
  5883. X      {
  5884. X      case '\n':
  5885. X        fputs ("\\n", fp);
  5886. X        break;
  5887. X      case '\r':
  5888. X        fputs ("\\r", fp);
  5889. X        break;
  5890. X      case '\b':
  5891. X        fputs ("\\b", fp);
  5892. X        break;
  5893. X      case '\0':
  5894. X        /* fputs("\\-",fp); */
  5895. X        break;
  5896. X      default:
  5897. X        fprintf (fp, "\\%03o", c);
  5898. X        break;
  5899. X      }
  5900. X    }
  5901. X  fputs ("'\n", fp);
  5902. X}
  5903. X
  5904. X#endif
  5905. X
  5906. Xint number_of_blocks_read = 0;
  5907. X
  5908. Xint number_of_new_records = 0;
  5909. Xint number_of_records_needed = 0;
  5910. X
  5911. Xunion record *new_block = 0;
  5912. Xunion record *save_block = 0;
  5913. X
  5914. Xvoid
  5915. Xjunk_archive ()
  5916. X{
  5917. X  int found_stuff = 0;
  5918. X  int status = 3;
  5919. X  int prev_status;
  5920. X  struct name *name;
  5921. X
  5922. X  /* int dummy_head; */
  5923. X  int number_of_records_to_skip = 0;
  5924. X  int number_of_records_to_keep = 0;
  5925. X  int number_of_kept_records_in_block;
  5926. X  int sub_status;
  5927. X  extern int write_archive_to_stdout;
  5928. X
  5929. X  /* fprintf(stderr,"Junk files\n"); */
  5930. X  name_gather ();
  5931. X  open_archive (2);
  5932. X
  5933. X  while (!found_stuff)
  5934. X    {
  5935. X      prev_status = status;
  5936. X      status = read_header ();
  5937. X      switch (status)
  5938. X    {
  5939. X    case EOF:
  5940. X      found_stuff = 1;
  5941. X      break;
  5942. X
  5943. X    case 0:
  5944. X      userec (head);
  5945. X      switch (prev_status)
  5946. X        {
  5947. X        case 3:
  5948. X          msg ("This doesn't look like a tar archive.");
  5949. X          /* FALL THROUGH */
  5950. X        case 2:
  5951. X        case 1:
  5952. X          msg ("Skipping to next header");
  5953. X          /* FALL THROUGH */
  5954. X        case 0:
  5955. X          break;
  5956. X        }
  5957. X      break;
  5958. X
  5959. X    case 1:
  5960. X      /* head->header.name[NAMSIZ-1] = '\0'; */
  5961. X      /* fprintf(stderr,"file %s\n",head->header.name); */
  5962. X      if ((name = name_scan (current_file_name)) == (struct name *) 0)
  5963. X        {
  5964. X          userec (head);
  5965. X          /* fprintf(stderr,"Skip %ld\n",(long)(hstat.st_size)); */
  5966. X          if (head->header.isextended)
  5967. X        skip_extended_headers ();
  5968. X          skip_file ((long) (hstat.st_size));
  5969. X          break;
  5970. X        }
  5971. X      name->found = 1;
  5972. X      found_stuff = 2;
  5973. X      break;
  5974. X
  5975. X    case 2:
  5976. X      found_stuff = 1;
  5977. X      break;
  5978. X    }
  5979. X    }
  5980. X  /* fprintf(stderr,"Out of first loop\n"); */
  5981. X
  5982. X  if (found_stuff != 2)
  5983. X    {
  5984. X      write_eot ();
  5985. X      close_archive ();
  5986. X      names_notfound ();
  5987. X      return;
  5988. X    }
  5989. X
  5990. X  if (write_archive_to_stdout)
  5991. X    write_archive_to_stdout = 0;
  5992. X  new_block = (union record *) malloc (blocksize);
  5993. X  if (new_block == 0)
  5994. X    {
  5995. X      msg ("Can't allocate secondary block of %d bytes", blocksize);
  5996. X      exit (EX_SYSTEM);
  5997. X    }
  5998. X
  5999. X  /* Save away records before this one in this block */
  6000. X  number_of_new_records = ar_record - ar_block;
  6001. X  number_of_records_needed = blocking - number_of_new_records;
  6002. X  if (number_of_new_records)
  6003. X    bcopy ((void *) ar_block, (void *) new_block, (number_of_new_records) * RECORDSIZE);
  6004. X
  6005. X  /* fprintf(stderr,"Saved %d recs, need %d more\n",number_of_new_records,number_of_records_needed); */
  6006. X  userec (head);
  6007. X  if (head->header.isextended)
  6008. X    skip_extended_headers ();
  6009. X  skip_file ((long) (hstat.st_size));
  6010. X  found_stuff = 0;
  6011. X  /* goto flush_file; */
  6012. X
  6013. X  for (;;)
  6014. X    {
  6015. X      /* Fill in a block */
  6016. X      /* another_file: */
  6017. X      if (ar_record == ar_last)
  6018. X    {
  6019. X      /* fprintf(stderr,"New block\n"); */
  6020. X      flush_archive ();
  6021. X      number_of_blocks_read++;
  6022. X    }
  6023. X      sub_status = read_header ();
  6024. X      /* fprintf(stderr,"Header type %d\n",sub_status); */
  6025. X
  6026. X      if (sub_status == 2 && f_ignorez)
  6027. X    {
  6028. X      userec (head);
  6029. X      continue;
  6030. X    }
  6031. X      if (sub_status == EOF || sub_status == 2)
  6032. X    {
  6033. X      found_stuff = 1;
  6034. X      bzero (new_block[number_of_new_records].charptr, RECORDSIZE * number_of_records_needed);
  6035. X      number_of_new_records += number_of_records_needed;
  6036. X      number_of_records_needed = 0;
  6037. X      write_block (0);
  6038. X      break;
  6039. X    }
  6040. X
  6041. X      if (sub_status == 0)
  6042. X    {
  6043. X      msg ("Deleting non-header from archive.");
  6044. X      userec (head);
  6045. X      continue;
  6046. X    }
  6047. X
  6048. X      /* Found another header.  Yipee! */
  6049. X      /* head->header.name[NAMSIZ-1] = '\0'; */
  6050. X      /* fprintf(stderr,"File %s ",head->header.name); */
  6051. X      if (name = name_scan (current_file_name))
  6052. X    {
  6053. X      name->found = 1;
  6054. X      /* fprintf(stderr,"Flush it\n"); */
  6055. X      /* flush_file: */
  6056. X      /* decode_header(head,&hstat,&dummy_head,0); */
  6057. X      userec (head);
  6058. X      number_of_records_to_skip = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE;
  6059. X      /* fprintf(stderr,"Flushing %d recs from %s\n",number_of_records_to_skip,head->header.name); */
  6060. X
  6061. X      while (ar_last - ar_record <= number_of_records_to_skip)
  6062. X        {
  6063. X
  6064. X          /* fprintf(stderr,"Block: %d <= %d  ",ar_last-ar_record,number_of_records_to_skip); */
  6065. X          number_of_records_to_skip -= (ar_last - ar_record);
  6066. X          flush_archive ();
  6067. X          number_of_blocks_read++;
  6068. X          /* fprintf(stderr,"Block %d left\n",number_of_records_to_skip); */
  6069. X        }
  6070. X      ar_record += number_of_records_to_skip;
  6071. X      /* fprintf(stderr,"Final %d\n",number_of_records_to_skip); */
  6072. X      number_of_records_to_skip = 0;
  6073. X      continue;
  6074. X    }
  6075. X
  6076. X      /* copy_header: */
  6077. X      new_block[number_of_new_records] = *head;
  6078. X      number_of_new_records++;
  6079. X      number_of_records_needed--;
  6080. X      number_of_records_to_keep = (hstat.st_size + RECORDSIZE - 1) / RECORDSIZE;
  6081. X      userec (head);
  6082. X      if (number_of_records_needed == 0)
  6083. X    write_block (1);
  6084. X      /* copy_data: */
  6085. X      number_of_kept_records_in_block = ar_last - ar_record;
  6086. X      if (number_of_kept_records_in_block > number_of_records_to_keep)
  6087. X    number_of_kept_records_in_block = number_of_records_to_keep;
  6088. X
  6089. X      /* fprintf(stderr,"Need %d kept_in %d keep %d\n",blocking,number_of_kept_records_in_block,number_of_records_to_keep); */
  6090. X
  6091. X      while (number_of_records_to_keep)
  6092. X    {
  6093. X      int n;
  6094. X
  6095. X      if (ar_record == ar_last)
  6096. X        {
  6097. X          /* fprintf(stderr,"Flush. . .\n"); */
  6098. X          fl_read ();
  6099. X          number_of_blocks_read++;
  6100. X          ar_record = ar_block;
  6101. X          number_of_kept_records_in_block = blocking;
  6102. X          if (number_of_kept_records_in_block > number_of_records_to_keep)
  6103. X        number_of_kept_records_in_block = number_of_records_to_keep;
  6104. X        }
  6105. X      n = number_of_kept_records_in_block;
  6106. X      if (n > number_of_records_needed)
  6107. X        n = number_of_records_needed;
  6108. X
  6109. X      /* fprintf(stderr,"Copying %d\n",n); */
  6110. X      bcopy ((void *) ar_record, (void *) (new_block + number_of_new_records), n * RECORDSIZE);
  6111. X      number_of_new_records += n;
  6112. X      number_of_records_needed -= n;
  6113. X      ar_record += n;
  6114. X      number_of_records_to_keep -= n;
  6115. X      number_of_kept_records_in_block -= n;
  6116. X      /* fprintf(stderr,"Now new %d  need %d  keep %d  keep_in %d rec %d/%d\n",
  6117. X number_of_new_records,number_of_records_needed,number_of_records_to_keep,
  6118. X number_of_kept_records_in_block,ar_record-ar_block,ar_last-ar_block); */
  6119. X
  6120. X      if (number_of_records_needed == 0)
  6121. X        {
  6122. X          write_block (1);
  6123. X        }
  6124. X    }
  6125. X    }
  6126. X
  6127. X  write_eot ();
  6128. X  close_archive ();
  6129. X  names_notfound ();
  6130. X}
  6131. X
  6132. Xvoid
  6133. Xwrite_block (f)
  6134. X     int f;
  6135. X{
  6136. X  /* fprintf(stderr,"Write block\n"); */
  6137. X  /* We've filled out a block.  Write it out. */
  6138. X
  6139. X  /* Backspace back to where we started. . . */
  6140. X  if (archive != STDIN)
  6141. X    (void) move_arch (-(number_of_blocks_read + 1));
  6142. X
  6143. X  save_block = ar_block;
  6144. X  ar_block = new_block;
  6145. X
  6146. X  if (archive == STDIN)
  6147. X    archive = STDOUT;
  6148. X  fl_write ();
  6149. X
  6150. X  if (archive == STDOUT)
  6151. X    archive = STDIN;
  6152. X  ar_block = save_block;
  6153. X
  6154. X  if (f)
  6155. X    {
  6156. X      /* Move the tape head back to where we were */
  6157. X      if (archive != STDIN)
  6158. X    (void) move_arch (number_of_blocks_read);
  6159. X      number_of_blocks_read--;
  6160. X    }
  6161. X
  6162. X  number_of_records_needed = blocking;
  6163. X  number_of_new_records = 0;
  6164. X}
  6165. X
  6166. X/* Move archive descriptor by n blocks worth.  If n is positive we move
  6167. X   forward, else we move negative.   If its a tape, MTIOCTOP had better
  6168. X   work.  If its something else, we try to seek on it.  If we can't
  6169. X   seek, we lose! */
  6170. Xint
  6171. Xmove_arch (n)
  6172. X     int n;
  6173. X{
  6174. X  long cur;
  6175. X
  6176. X#ifdef MTIOCTOP
  6177. X  struct mtop t;
  6178. X  int er;
  6179. X
  6180. X  if (n > 0)
  6181. X    {
  6182. X      t.mt_op = MTFSR;
  6183. X      t.mt_count = n;
  6184. X    }
  6185. X  else
  6186. X    {
  6187. X      t.mt_op = MTBSR;
  6188. X      t.mt_count = -n;
  6189. X    }
  6190. X  if ((er = rmtioctl (archive, MTIOCTOP, &t)) >= 0)
  6191. X    return 1;
  6192. X  if (errno == EIO && (er = rmtioctl (archive, MTIOCTOP, &t)) >= 0)
  6193. X    return 1;
  6194. X#endif
  6195. X
  6196. X  cur = rmtlseek (archive, 0L, 1);
  6197. X  cur += blocksize * n;
  6198. X
  6199. X  /* fprintf(stderr,"Fore to %x\n",cur); */
  6200. X  if (rmtlseek (archive, cur, 0) != cur)
  6201. X    {
  6202. X      /* Lseek failed.  Try a different method */
  6203. X      msg ("Couldn't re-position archive file.");
  6204. X      exit (EX_BADARCH);
  6205. X    }
  6206. X  return 3;
  6207. X}
  6208. END_OF_FILE
  6209. if test 13900 -ne `wc -c <'update.c'`; then
  6210.     echo shar: \"'update.c'\" unpacked with wrong size!
  6211. fi
  6212. # end of 'update.c'
  6213. fi
  6214. if test -f 'gnu.c' -a "${1}" != "-c" ; then 
  6215.   echo shar: Will not clobber existing file \"'gnu.c'\"
  6216. else
  6217. echo shar: Extracting \"'gnu.c'\" \(13964 characters\)
  6218. sed "s/^X//" >'gnu.c' <<'END_OF_FILE'
  6219. X/* GNU dump extensions to tar.
  6220. X   Copyright (C) 1988, 1992, 1993 Free Software Foundation
  6221. X
  6222. XThis file is part of GNU Tar.
  6223. X
  6224. XGNU Tar is free software; you can redistribute it and/or modify
  6225. Xit under the terms of the GNU General Public License as published by
  6226. Xthe Free Software Foundation; either version 2, or (at your option)
  6227. Xany later version.
  6228. X
  6229. XGNU Tar is distributed in the hope that it will be useful,
  6230. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  6231. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  6232. XGNU General Public License for more details.
  6233. X
  6234. XYou should have received a copy of the GNU General Public License
  6235. Xalong with GNU Tar; see the file COPYING.  If not, write to
  6236. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  6237. X
  6238. X#include <stdio.h>
  6239. X#include <sys/types.h>
  6240. X#include <ctype.h>
  6241. X#include <errno.h>
  6242. X#ifndef STDC_HEADERS
  6243. Xextern int errno;
  6244. X#endif
  6245. X#include <time.h>
  6246. Xtime_t time ();
  6247. X
  6248. X#include "tar.h"
  6249. X#include "port.h"
  6250. X
  6251. X#ifndef S_ISLNK
  6252. X#define lstat stat
  6253. X#endif
  6254. X
  6255. Xextern time_t new_time;
  6256. Xextern FILE *msg_file;
  6257. X
  6258. Xvoid addname ();
  6259. Xint check_exclude ();
  6260. Xextern PTR ck_malloc ();
  6261. Xextern PTR ck_realloc ();
  6262. Xint confirm ();
  6263. Xextern PTR init_buffer ();
  6264. Xextern char *get_buffer ();
  6265. Xint is_dot_or_dotdot ();
  6266. Xextern void add_buffer ();
  6267. Xextern void flush_buffer ();
  6268. Xvoid name_gather ();
  6269. Xint recursively_delete ();
  6270. Xvoid skip_file ();
  6271. Xchar *un_quote_string ();
  6272. X
  6273. Xextern char *new_name ();
  6274. X
  6275. Xstatic void add_dir_name ();
  6276. X
  6277. Xstruct dirname
  6278. X  {
  6279. X    struct dirname *next;
  6280. X    char *name;
  6281. X    char *dir_text;
  6282. X    int dev;
  6283. X    int ino;
  6284. X    int allnew;
  6285. X  };
  6286. Xstatic struct dirname *dir_list;
  6287. Xstatic time_t this_time;
  6288. X
  6289. Xvoid
  6290. Xadd_dir (name, dev, ino, text)
  6291. X     char *name;
  6292. X     char *text;
  6293. X     dev_t dev;
  6294. X     ino_t ino;
  6295. X{
  6296. X  struct dirname *dp;
  6297. X
  6298. X  dp = (struct dirname *) ck_malloc (sizeof (struct dirname));
  6299. X  if (!dp)
  6300. X    abort ();
  6301. X  dp->next = dir_list;
  6302. X  dir_list = dp;
  6303. X  dp->dev = dev;
  6304. X  dp->ino = ino;
  6305. X  dp->name = ck_malloc (strlen (name) + 1);
  6306. X  strcpy (dp->name, name);
  6307. X  dp->dir_text = text;
  6308. X  dp->allnew = 0;
  6309. X}
  6310. X
  6311. Xvoid
  6312. Xread_dir_file ()
  6313. X{
  6314. X  int dev;
  6315. X  int ino;
  6316. X  char *strp;
  6317. X  FILE *fp;
  6318. X  char buf[512];
  6319. X  static char *path = 0;
  6320. X
  6321. X  if (path == 0)
  6322. X    path = ck_malloc (PATH_MAX);
  6323. X  time (&this_time);
  6324. X  if (gnu_dumpfile[0] != '/')
  6325. X    {
  6326. X#if defined(__MSDOS__) || defined(HAVE_GETCWD) || defined(_POSIX_VERSION)
  6327. X      if (!getcwd (path, PATH_MAX))
  6328. X    {
  6329. X      msg ("Couldn't get current directory.");
  6330. X      exit (EX_SYSTEM);
  6331. X    }
  6332. X#else
  6333. X      char *getwd ();
  6334. X
  6335. X      if (!getwd (path))
  6336. X    {
  6337. X      msg ("Couldn't get current directory: %s", path);
  6338. X      exit (EX_SYSTEM);
  6339. X    }
  6340. X#endif
  6341. X      /* If this doesn't fit, we're in serious trouble */
  6342. X      strcat (path, "/");
  6343. X      strcat (path, gnu_dumpfile);
  6344. X      gnu_dumpfile = path;
  6345. X    }
  6346. X  fp = fopen (gnu_dumpfile, "r");
  6347. X  if (fp == 0 && errno != ENOENT)
  6348. X    {
  6349. X      msg_perror ("Can't open %s", gnu_dumpfile);
  6350. X      return;
  6351. X    }
  6352. X  if (!fp)
  6353. X    return;
  6354. X  fgets (buf, sizeof (buf), fp);
  6355. X  if (!f_new_files)
  6356. X    {
  6357. X      f_new_files++;
  6358. X      new_time = atol (buf);
  6359. X    }
  6360. X  while (fgets (buf, sizeof (buf), fp))
  6361. X    {
  6362. X      strp = &buf[strlen (buf)];
  6363. X      if (strp[-1] == '\n')
  6364. X    strp[-1] = '\0';
  6365. X      strp = buf;
  6366. X      dev = atol (strp);
  6367. X      while (isdigit (*strp))
  6368. X    strp++;
  6369. X      ino = atol (strp);
  6370. X      while (isspace (*strp))
  6371. X    strp++;
  6372. X      while (isdigit (*strp))
  6373. X    strp++;
  6374. X      strp++;
  6375. X      add_dir (un_quote_string (strp), dev, ino, (char *) 0);
  6376. X    }
  6377. X  fclose (fp);
  6378. X}
  6379. X
  6380. Xvoid
  6381. Xwrite_dir_file ()
  6382. X{
  6383. X  FILE *fp;
  6384. X  struct dirname *dp;
  6385. X  char *str;
  6386. X  extern char *quote_copy_string ();
  6387. X
  6388. X  fp = fopen (gnu_dumpfile, "w");
  6389. X  if (fp == 0)
  6390. X    {
  6391. X      msg_perror ("Can't write to %s", gnu_dumpfile);
  6392. X      return;
  6393. X    }
  6394. X  fprintf (fp, "%lu\n", this_time);
  6395. X  for (dp = dir_list; dp; dp = dp->next)
  6396. X    {
  6397. X      if (!dp->dir_text)
  6398. X    continue;
  6399. X      str = quote_copy_string (dp->name);
  6400. X      if (str)
  6401. X    {
  6402. X      fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, str);
  6403. X      free (str);
  6404. X    }
  6405. X      else
  6406. X    fprintf (fp, "%u %u %s\n", dp->dev, dp->ino, dp->name);
  6407. X    }
  6408. X  fclose (fp);
  6409. X}
  6410. X
  6411. Xstruct dirname *
  6412. Xget_dir (name)
  6413. X     char *name;
  6414. X{
  6415. X  struct dirname *dp;
  6416. X
  6417. X  for (dp = dir_list; dp; dp = dp->next)
  6418. X    {
  6419. X      if (!strcmp (dp->name, name))
  6420. X    return dp;
  6421. X    }
  6422. X  return 0;
  6423. X}
  6424. X
  6425. X
  6426. X/* Collect all the names from argv[] (or whatever), then expand them into
  6427. X   a directory tree, and put all the directories at the beginning. */
  6428. Xvoid
  6429. Xcollect_and_sort_names ()
  6430. X{
  6431. X  struct name *n, *n_next;
  6432. X  int num_names;
  6433. X  struct stat statbuf;
  6434. X  int name_cmp ();
  6435. X  char *merge_sort ();
  6436. X
  6437. X  name_gather ();
  6438. X
  6439. X  if (gnu_dumpfile)
  6440. X    read_dir_file ();
  6441. X  if (!namelist)
  6442. X    addname (".");
  6443. X  for (n = namelist; n; n = n_next)
  6444. X    {
  6445. X      n_next = n->next;
  6446. X      if (n->found || n->dir_contents)
  6447. X    continue;
  6448. X      if (n->regexp)        /* FIXME just skip regexps for now */
  6449. X    continue;
  6450. X      if (n->change_dir)
  6451. X    if (chdir (n->change_dir) < 0)
  6452. X      {
  6453. X        msg_perror ("can't chdir to %s", n->change_dir);
  6454. X        continue;
  6455. X      }
  6456. X
  6457. X#ifdef AIX
  6458. X      if (statx (n->name, &statbuf, STATSIZE, STX_HIDDEN | STX_LINK))
  6459. X#else
  6460. X      if (lstat (n->name, &statbuf) < 0)
  6461. X#endif /* AIX */
  6462. X    {
  6463. X      msg_perror ("can't stat %s", n->name);
  6464. X      continue;
  6465. X    }
  6466. X      if (S_ISDIR (statbuf.st_mode))
  6467. X    {
  6468. X      n->found++;
  6469. X      add_dir_name (n->name, statbuf.st_dev);
  6470. X    }
  6471. X    }
  6472. X
  6473. X  num_names = 0;
  6474. X  for (n = namelist; n; n = n->next)
  6475. X    num_names++;
  6476. X  namelist = (struct name *) merge_sort ((PTR) namelist, num_names, (char *) (&(namelist->next)) - (char *) namelist, name_cmp);
  6477. X
  6478. X  for (n = namelist; n; n = n->next)
  6479. X    {
  6480. X      n->found = 0;
  6481. X    }
  6482. X  if (gnu_dumpfile)
  6483. X    write_dir_file ();
  6484. X}
  6485. X
  6486. Xint
  6487. Xname_cmp (n1, n2)
  6488. X     struct name *n1, *n2;
  6489. X{
  6490. X  if (n1->found)
  6491. X    {
  6492. X      if (n2->found)
  6493. X    return strcmp (n1->name, n2->name);
  6494. X      else
  6495. X    return -1;
  6496. X    }
  6497. X  else if (n2->found)
  6498. X    return 1;
  6499. X  else
  6500. X    return strcmp (n1->name, n2->name);
  6501. X}
  6502. X
  6503. Xint
  6504. Xdirent_cmp (p1, p2)
  6505. X     const PTR p1;
  6506. X     const PTR p2;
  6507. X{
  6508. X  char *frst, *scnd;
  6509. X
  6510. X  frst = (*(char **) p1) + 1;
  6511. X  scnd = (*(char **) p2) + 1;
  6512. X
  6513. X  return strcmp (frst, scnd);
  6514. X}
  6515. X
  6516. Xchar *
  6517. Xget_dir_contents (p, device)
  6518. X     char *p;
  6519. X     int device;
  6520. X{
  6521. X  DIR *dirp;
  6522. X  register struct dirent *d;
  6523. X  char *new_buf;
  6524. X  char *namebuf;
  6525. X  int bufsiz;
  6526. X  int len;
  6527. X  PTR the_buffer;
  6528. X  char *buf;
  6529. X  size_t n_strs;
  6530. X  /*    int n_size;*/
  6531. X  char *p_buf;
  6532. X  char **vec, **p_vec;
  6533. X
  6534. X  extern int errno;
  6535. X
  6536. X  errno = 0;
  6537. X  dirp = opendir (p);
  6538. X  bufsiz = strlen (p) + NAMSIZ;
  6539. X  namebuf = ck_malloc (bufsiz + 2);
  6540. X  if (!dirp)
  6541. X    {
  6542. X      if (errno)
  6543. X    msg_perror ("can't open directory %s", p);
  6544. X      else
  6545. X    msg ("error opening directory %s", p);
  6546. X      new_buf = NULL;
  6547. X    }
  6548. X  else
  6549. X    {
  6550. X      struct dirname *dp;
  6551. X      int all_children;
  6552. X
  6553. X      dp = get_dir (p);
  6554. X      all_children = dp ? dp->allnew : 0;
  6555. X      (void) strcpy (namebuf, p);
  6556. X      if (p[strlen (p) - 1] != '/')
  6557. X    (void) strcat (namebuf, "/");
  6558. X      len = strlen (namebuf);
  6559. X
  6560. X      the_buffer = init_buffer ();
  6561. X      while (d = readdir (dirp))
  6562. X    {
  6563. X      struct stat hs;
  6564. X
  6565. X      /* Skip . and .. */
  6566. X      if (is_dot_or_dotdot (d->d_name))
  6567. X        continue;
  6568. X      if (NLENGTH (d) + len >= bufsiz)
  6569. X        {
  6570. X          bufsiz += NAMSIZ;
  6571. X          namebuf = ck_realloc (namebuf, bufsiz + 2);
  6572. X        }
  6573. X      (void) strcpy (namebuf + len, d->d_name);
  6574. X#ifdef AIX
  6575. X      if (0 != f_follow_links ?
  6576. X          statx (namebuf, &hs, STATSIZE, STX_HIDDEN) :
  6577. X          statx (namebuf, &hs, STATSIZE, STX_HIDDEN | STX_LINK))
  6578. X#else
  6579. X      if (0 != f_follow_links ? stat (namebuf, &hs) : lstat (namebuf, &hs))
  6580. X#endif
  6581. X        {
  6582. X          msg_perror ("can't stat %s", namebuf);
  6583. X          continue;
  6584. X        }
  6585. X      if ((f_local_filesys && device != hs.st_dev)
  6586. X          || (f_exclude && check_exclude (namebuf)))
  6587. X        add_buffer (the_buffer, "N", 1);
  6588. X#ifdef AIX
  6589. X      else if (S_ISHIDDEN (hs.st_mode))
  6590. X        {
  6591. X          add_buffer (the_buffer, "D", 1);
  6592. X          strcat (d->d_name, "A");
  6593. X          d->d_namlen++;
  6594. X        }
  6595. X#endif /* AIX */
  6596. X      else if (S_ISDIR (hs.st_mode))
  6597. X        {
  6598. X          if (dp = get_dir (namebuf))
  6599. X        {
  6600. X          if (dp->dev != hs.st_dev
  6601. X              || dp->ino != hs.st_ino)
  6602. X            {
  6603. X              if (f_verbose)
  6604. X            msg ("directory %s has been renamed.", namebuf);
  6605. X              dp->allnew = 1;
  6606. X              dp->dev = hs.st_dev;
  6607. X              dp->ino = hs.st_ino;
  6608. X            }
  6609. X          dp->dir_text = "";
  6610. X        }
  6611. X          else
  6612. X        {
  6613. X          if (f_verbose)
  6614. X            msg ("Directory %s is new", namebuf);
  6615. X          add_dir (namebuf, hs.st_dev, hs.st_ino, "");
  6616. X          dp = get_dir (namebuf);
  6617. X          dp->allnew = 1;
  6618. X        }
  6619. X          if (all_children)
  6620. X        dp->allnew = 1;
  6621. X
  6622. X          add_buffer (the_buffer, "D", 1);
  6623. X        }
  6624. X      else if (!all_children
  6625. X           && f_new_files
  6626. X           && new_time > hs.st_mtime
  6627. X           && (f_new_files > 1
  6628. X               || new_time > hs.st_ctime))
  6629. X        add_buffer (the_buffer, "N", 1);
  6630. X      else
  6631. X        add_buffer (the_buffer, "Y", 1);
  6632. X      add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
  6633. X    }
  6634. X      add_buffer (the_buffer, "\000\000", 2);
  6635. X      closedir (dirp);
  6636. X
  6637. X      /* Well, we've read in the contents of the dir, now sort them */
  6638. X      buf = get_buffer (the_buffer);
  6639. X      if (buf[0] == '\0')
  6640. X    {
  6641. X      flush_buffer (the_buffer);
  6642. X      new_buf = NULL;
  6643. X    }
  6644. X      else
  6645. X    {
  6646. X      n_strs = 0;
  6647. X      for (p_buf = buf; *p_buf;)
  6648. X        {
  6649. X          int tmp;
  6650. X
  6651. X          tmp = strlen (p_buf) + 1;
  6652. X          n_strs++;
  6653. X          p_buf += tmp;
  6654. X        }
  6655. X      vec = (char **) ck_malloc (sizeof (char *) * (n_strs + 1));
  6656. X      for (p_vec = vec, p_buf = buf; *p_buf; p_buf += strlen (p_buf) + 1)
  6657. X        *p_vec++ = p_buf;
  6658. X      *p_vec = 0;
  6659. X      qsort ((PTR) vec, n_strs, sizeof (char *), dirent_cmp);
  6660. X      new_buf = (char *) ck_malloc (p_buf - buf + 2);
  6661. X      for (p_vec = vec, p_buf = new_buf; *p_vec; p_vec++)
  6662. X        {
  6663. X          char *p_tmp;
  6664. X
  6665. X          for (p_tmp = *p_vec; *p_buf++ = *p_tmp++;)
  6666. X        ;
  6667. X        }
  6668. X      *p_buf++ = '\0';
  6669. X      free (vec);
  6670. X      flush_buffer (the_buffer);
  6671. X    }
  6672. X    }
  6673. X  free (namebuf);
  6674. X  return new_buf;
  6675. X}
  6676. X
  6677. X/* p is a directory.  Add all the files in P to the namelist.  If any of the
  6678. X   files is a directory, recurse on the subdirectory. . . */
  6679. Xstatic void
  6680. Xadd_dir_name (p, device)
  6681. X     char *p;
  6682. X     int device;
  6683. X{
  6684. X  char *new_buf;
  6685. X  char *p_buf;
  6686. X
  6687. X  char *namebuf;
  6688. X  int buflen;
  6689. X  register int len;
  6690. X  int sublen;
  6691. X
  6692. X  /*    PTR the_buffer;*/
  6693. X
  6694. X  /*    char *buf;*/
  6695. X  /*    char **vec,**p_vec;*/
  6696. X  /*    int n_strs,n_size;*/
  6697. X
  6698. X  struct name *n;
  6699. X
  6700. X  int dirent_cmp ();
  6701. X
  6702. X  new_buf = get_dir_contents (p, device);
  6703. X
  6704. X  for (n = namelist; n; n = n->next)
  6705. X    {
  6706. X      if (!strcmp (n->name, p))
  6707. X    {
  6708. X      n->dir_contents = new_buf ? new_buf : "\0\0\0\0";
  6709. X      break;
  6710. X    }
  6711. X    }
  6712. X
  6713. X  if (new_buf)
  6714. X    {
  6715. X      len = strlen (p);
  6716. X      buflen = NAMSIZ <= len ? len + NAMSIZ : NAMSIZ;
  6717. X      namebuf = ck_malloc (buflen + 1);
  6718. X
  6719. X      (void) strcpy (namebuf, p);
  6720. X      if (namebuf[len - 1] != '/')
  6721. X    {
  6722. X      namebuf[len++] = '/';
  6723. X      namebuf[len] = '\0';
  6724. X    }
  6725. X      for (p_buf = new_buf; *p_buf; p_buf += sublen + 1)
  6726. X    {
  6727. X      sublen = strlen (p_buf);
  6728. X      if (*p_buf == 'D')
  6729. X        {
  6730. X          if (len + sublen >= buflen)
  6731. X        {
  6732. X          buflen += NAMSIZ;
  6733. X          namebuf = ck_realloc (namebuf, buflen + 1);
  6734. X        }
  6735. X          (void) strcpy (namebuf + len, p_buf + 1);
  6736. X          addname (namebuf);
  6737. X          add_dir_name (namebuf, device);
  6738. X        }
  6739. X    }
  6740. X      free (namebuf);
  6741. X    }
  6742. X}
  6743. X
  6744. X/* Returns non-zero if p is . or ..   This could be a macro for speed. */
  6745. Xint
  6746. Xis_dot_or_dotdot (p)
  6747. X     char *p;
  6748. X{
  6749. X  return (p[0] == '.' && (p[1] == '\0' || (p[1] == '.' && p[2] == '\0')));
  6750. X}
  6751. X
  6752. X
  6753. X
  6754. X
  6755. X
  6756. X
  6757. Xvoid
  6758. Xgnu_restore (skipcrud)
  6759. X     int skipcrud;
  6760. X{
  6761. X  char *current_dir;
  6762. X  /*    int current_dir_length; */
  6763. X
  6764. X  char *archive_dir;
  6765. X  /*    int archive_dir_length; */
  6766. X  PTR the_buffer;
  6767. X  char *p;
  6768. X  DIR *dirp;
  6769. X  struct dirent *d;
  6770. X  char *cur, *arc;
  6771. X  extern struct stat hstat;    /* Stat struct corresponding */
  6772. X  long size, copied;
  6773. X  char *from, *to;
  6774. X  extern union record *head;
  6775. X
  6776. X  dirp = opendir (skipcrud + current_file_name);
  6777. X
  6778. X  if (!dirp)
  6779. X    {
  6780. X      /* The directory doesn't exist now.  It'll be created.
  6781. X               In any case, we don't have to delete any files out
  6782. X               of it */
  6783. X      skip_file ((long) hstat.st_size);
  6784. X      return;
  6785. X    }
  6786. X
  6787. X  the_buffer = init_buffer ();
  6788. X  while (d = readdir (dirp))
  6789. X    {
  6790. X      if (is_dot_or_dotdot (d->d_name))
  6791. X    continue;
  6792. X
  6793. X      add_buffer (the_buffer, d->d_name, (int) (NLENGTH (d) + 1));
  6794. X    }
  6795. X  closedir (dirp);
  6796. X  add_buffer (the_buffer, "", 1);
  6797. X
  6798. X  current_dir = get_buffer (the_buffer);
  6799. X  archive_dir = (char *) ck_malloc (hstat.st_size);
  6800. X  if (archive_dir == 0)
  6801. X    {
  6802. X      msg ("Can't allocate %d bytes for restore", hstat.st_size);
  6803. X      skip_file ((long) hstat.st_size);
  6804. X      return;
  6805. X    }
  6806. X  to = archive_dir;
  6807. X  for (size = hstat.st_size; size > 0; size -= copied)
  6808. X    {
  6809. X      from = findrec ()->charptr;
  6810. X      if (!from)
  6811. X    {
  6812. X      msg ("Unexpected EOF in archive\n");
  6813. X      break;
  6814. X    }
  6815. X      copied = endofrecs ()->charptr - from;
  6816. X      if (copied > size)
  6817. X    copied = size;
  6818. X      bcopy ((PTR) from, (PTR) to, (int) copied);
  6819. X      to += copied;
  6820. X      userec ((union record *) (from + copied - 1));
  6821. X    }
  6822. X
  6823. X  for (cur = current_dir; *cur; cur += strlen (cur) + 1)
  6824. X    {
  6825. X      for (arc = archive_dir; *arc; arc += strlen (arc) + 1)
  6826. X    {
  6827. X      arc++;
  6828. X      if (!strcmp (arc, cur))
  6829. X        break;
  6830. X    }
  6831. X      if (*arc == '\0')
  6832. X    {
  6833. X      p = new_name (skipcrud + current_file_name, cur);
  6834. X      if (f_confirm && !confirm ("delete", p))
  6835. X        {
  6836. X          free (p);
  6837. X          continue;
  6838. X        }
  6839. X      if (f_verbose)
  6840. X        fprintf (msg_file, "%s: deleting %s\n", tar, p);
  6841. X      if (recursively_delete (p))
  6842. X        {
  6843. X          msg ("%s: Error while deleting %s\n", tar, p);
  6844. X        }
  6845. X      free (p);
  6846. X    }
  6847. X
  6848. X    }
  6849. X  flush_buffer (the_buffer);
  6850. X  free (archive_dir);
  6851. X}
  6852. X
  6853. Xint
  6854. Xrecursively_delete (path)
  6855. X     char *path;
  6856. X{
  6857. X  struct stat sbuf;
  6858. X  DIR *dirp;
  6859. X  struct dirent *dp;
  6860. X  char *path_buf;
  6861. X  /* int path_len; */
  6862. X
  6863. X
  6864. X  if (lstat (path, &sbuf) < 0)
  6865. X    return 1;
  6866. X  if (S_ISDIR (sbuf.st_mode))
  6867. X    {
  6868. X
  6869. X      /* path_len=strlen(path); */
  6870. X      dirp = opendir (path);
  6871. X      if (dirp == 0)
  6872. X    return 1;
  6873. X      while (dp = readdir (dirp))
  6874. X    {
  6875. X      if (is_dot_or_dotdot (dp->d_name))
  6876. X        continue;
  6877. X      path_buf = new_name (path, dp->d_name);
  6878. X      if (recursively_delete (path_buf))
  6879. X        {
  6880. X          free (path_buf);
  6881. X          closedir (dirp);
  6882. X          return 1;
  6883. X        }
  6884. X      free (path_buf);
  6885. X    }
  6886. X      closedir (dirp);
  6887. X
  6888. X      if (rmdir (path) < 0)
  6889. X    return 1;
  6890. X      return 0;
  6891. X    }
  6892. X  if (unlink (path) < 0)
  6893. X    return 1;
  6894. X  return 0;
  6895. X}
  6896. END_OF_FILE
  6897. if test 13964 -ne `wc -c <'gnu.c'`; then
  6898.     echo shar: \"'gnu.c'\" unpacked with wrong size!
  6899. fi
  6900. # end of 'gnu.c'
  6901. fi
  6902. if test -f 'mangle.c' -a "${1}" != "-c" ; then 
  6903.   echo shar: Will not clobber existing file \"'mangle.c'\"
  6904. else
  6905. echo shar: Extracting \"'mangle.c'\" \(6635 characters\)
  6906. sed "s/^X//" >'mangle.c' <<'END_OF_FILE'
  6907. X/* mangle.c -- encode long filenames
  6908. X   Copyright (C) 1988, 1992 Free Software Foundation
  6909. X
  6910. XThis file is part of GNU Tar.
  6911. X
  6912. XGNU Tar is free software; you can redistribute it and/or modify
  6913. Xit under the terms of the GNU General Public License as published by
  6914. Xthe Free Software Foundation; either version 2, or (at your option)
  6915. Xany later version.
  6916. X
  6917. XGNU Tar is distributed in the hope that it will be useful,
  6918. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  6919. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  6920. XGNU General Public License for more details.
  6921. X
  6922. XYou should have received a copy of the GNU General Public License
  6923. Xalong with GNU Tar; see the file COPYING.  If not, write to
  6924. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  6925. X
  6926. X#include <stdio.h>
  6927. X#include <sys/types.h>
  6928. X#include <time.h>
  6929. Xtime_t time ();
  6930. X
  6931. X#include "tar.h"
  6932. X#include "port.h"
  6933. X
  6934. Xvoid add_buffer ();
  6935. Xextern PTR ck_malloc ();
  6936. Xvoid finish_header ();
  6937. Xextern PTR init_buffer ();
  6938. Xextern char *quote_copy_string ();
  6939. Xextern char *get_buffer ();
  6940. Xchar *un_quote_string ();
  6941. X
  6942. Xextern union record *start_header ();
  6943. X
  6944. Xextern struct stat hstat;    /* Stat struct corresponding */
  6945. X
  6946. Xstruct mangled
  6947. X  {
  6948. X    struct mangled *next;
  6949. X    int type;
  6950. X    char mangled[NAMSIZ];
  6951. X    char *linked_to;
  6952. X    char normal[1];
  6953. X  };
  6954. X
  6955. X
  6956. X/* Should use a hash table, etc. .  */
  6957. Xstruct mangled *first_mangle;
  6958. Xint mangled_num = 0;
  6959. X
  6960. X#if 0                /* Deleted because there is now a better way to do all this */
  6961. X
  6962. Xchar *
  6963. Xfind_mangled (name)
  6964. X     char *name;
  6965. X{
  6966. X  struct mangled *munge;
  6967. X
  6968. X  for (munge = first_mangle; munge; munge = munge->next)
  6969. X    if (!strcmp (name, munge->normal))
  6970. X      return munge->mangled;
  6971. X  return 0;
  6972. X}
  6973. X
  6974. X
  6975. X#ifdef S_ISLNK
  6976. Xvoid
  6977. Xadd_symlink_mangle (symlink, linkto, buffer)
  6978. X     char *symlink;
  6979. X     char *linkto;
  6980. X     char *buffer;
  6981. X{
  6982. X  struct mangled *munge, *kludge;
  6983. X
  6984. X  munge = (struct mangled *) ck_malloc (sizeof (struct mangled) + strlen (symlink) + strlen (linkto) + 2);
  6985. X  if (!first_mangle)
  6986. X    first_mangle = munge;
  6987. X  else
  6988. X    {
  6989. X      for (kludge = first_mangle; kludge->next; kludge = kludge->next)
  6990. X    ;
  6991. X      kludge->next = munge;
  6992. X    }
  6993. X  munge->type = 1;
  6994. X  munge->next = 0;
  6995. X  strcpy (munge->normal, symlink);
  6996. X  munge->linked_to = munge->normal + strlen (symlink) + 1;
  6997. X  strcpy (munge->linked_to, linkto);
  6998. X  sprintf (munge->mangled, "@@MaNgLeD.%d", mangled_num++);
  6999. X  strncpy (buffer, munge->mangled, NAMSIZ);
  7000. X}
  7001. X
  7002. X#endif
  7003. X
  7004. Xvoid
  7005. Xadd_mangle (name, buffer)
  7006. X     char *name;
  7007. X     char *buffer;
  7008. X{
  7009. X  struct mangled *munge, *kludge;
  7010. X
  7011. X  munge = (struct mangled *) ck_malloc (sizeof (struct mangled) + strlen (name));
  7012. X  if (!first_mangle)
  7013. X    first_mangle = munge;
  7014. X  else
  7015. X    {
  7016. X      for (kludge = first_mangle; kludge->next; kludge = kludge->next)
  7017. X    ;
  7018. X      kludge->next = munge;
  7019. X    }
  7020. X  munge->next = 0;
  7021. X  munge->type = 0;
  7022. X  strcpy (munge->normal, name);
  7023. X  sprintf (munge->mangled, "@@MaNgLeD.%d", mangled_num++);
  7024. X  strncpy (buffer, munge->mangled, NAMSIZ);
  7025. X}
  7026. X
  7027. Xvoid
  7028. Xwrite_mangled ()
  7029. X{
  7030. X  struct mangled *munge;
  7031. X  struct stat hstat;
  7032. X  union record *header;
  7033. X  char *ptr1, *ptr2;
  7034. X  PTR the_buffer;
  7035. X  int size;
  7036. X  int bufsize;
  7037. X
  7038. X  if (!first_mangle)
  7039. X    return;
  7040. X  the_buffer = init_buffer ();
  7041. X  for (munge = first_mangle, size = 0; munge; munge = munge->next)
  7042. X    {
  7043. X      ptr1 = quote_copy_string (munge->normal);
  7044. X      if (!ptr1)
  7045. X    ptr1 = munge->normal;
  7046. X      if (munge->type)
  7047. X    {
  7048. X      add_buffer (the_buffer, "Symlink ", 8);
  7049. X      add_buffer (the_buffer, ptr1, strlen (ptr1));
  7050. X      add_buffer (the_buffer, " to ", 4);
  7051. X
  7052. X      if (ptr2 = quote_copy_string (munge->linked_to))
  7053. X        {
  7054. X          add_buffer (the_buffer, ptr2, strlen (ptr2));
  7055. X          free (ptr2);
  7056. X        }
  7057. X      else
  7058. X        add_buffer (the_buffer, munge->linked_to, strlen (munge->linked_to));
  7059. X    }
  7060. X      else
  7061. X    {
  7062. X      add_buffer (the_buffer, "Rename ", 7);
  7063. X      add_buffer (the_buffer, munge->mangled, strlen (munge->mangled));
  7064. X      add_buffer (the_buffer, " to ", 4);
  7065. X      add_buffer (the_buffer, ptr1, strlen (ptr1));
  7066. X    }
  7067. X      add_buffer (the_buffer, "\n", 1);
  7068. X      if (ptr1 != munge->normal)
  7069. X    free (ptr1);
  7070. X    }
  7071. X
  7072. X  bzero (&hstat, sizeof (struct stat));
  7073. X  hstat.st_atime = hstat.st_mtime = hstat.st_ctime = time (0);
  7074. X  ptr1 = get_buffer (the_buffer);
  7075. X  hstat.st_size = strlen (ptr1);
  7076. X
  7077. X  header = start_header ("././@MaNgLeD_NaMeS", &hstat);
  7078. X  header->header.linkflag = LF_NAMES;
  7079. X  finish_header (header);
  7080. X  size = hstat.st_size;
  7081. X  header = findrec ();
  7082. X  bufsize = endofrecs ()->charptr - header->charptr;
  7083. X
  7084. X  while (bufsize < size)
  7085. X    {
  7086. X      bcopy (ptr1, header->charptr, bufsize);
  7087. X      ptr1 += bufsize;
  7088. X      size -= bufsize;
  7089. X      userec (header + (bufsize - 1) / RECORDSIZE);
  7090. X      header = findrec ();
  7091. X      bufsize = endofrecs ()->charptr - header->charptr;
  7092. X    }
  7093. X  bcopy (ptr1, header->charptr, size);
  7094. X  bzero (header->charptr + size, bufsize - size);
  7095. X  userec (header + (size - 1) / RECORDSIZE);
  7096. X}
  7097. X
  7098. X#endif
  7099. X
  7100. Xvoid
  7101. Xextract_mangle (head)
  7102. X     union record *head;
  7103. X{
  7104. X  char *buf;
  7105. X  char *fromtape;
  7106. X  char *to;
  7107. X  char *ptr, *ptrend;
  7108. X  char *nam1, *nam1end;
  7109. X  int size;
  7110. X  int copied;
  7111. X
  7112. X  size = hstat.st_size;
  7113. X  buf = to = ck_malloc (size + 1);
  7114. X  buf[size] = '\0';
  7115. X  while (size > 0)
  7116. X    {
  7117. X      fromtape = findrec ()->charptr;
  7118. X      if (fromtape == 0)
  7119. X    {
  7120. X      msg ("Unexpected EOF in mangled names!");
  7121. X      return;
  7122. X    }
  7123. X      copied = endofrecs ()->charptr - fromtape;
  7124. X      if (copied > size)
  7125. X    copied = size;
  7126. X      bcopy (fromtape, to, copied);
  7127. X      to += copied;
  7128. X      size -= copied;
  7129. X      userec ((union record *) (fromtape + copied - 1));
  7130. X    }
  7131. X  for (ptr = buf; *ptr; ptr = ptrend)
  7132. X    {
  7133. X      ptrend = index (ptr, '\n');
  7134. X      *ptrend++ = '\0';
  7135. X
  7136. X      if (!strncmp (ptr, "Rename ", 7))
  7137. X    {
  7138. X      nam1 = ptr + 7;
  7139. X      nam1end = index (nam1, ' ');
  7140. X      while (strncmp (nam1end, " to ", 4))
  7141. X        {
  7142. X          nam1end++;
  7143. X          nam1end = index (nam1end, ' ');
  7144. X        }
  7145. X      *nam1end = '\0';
  7146. X      if (ptrend[-2] == '/')
  7147. X        ptrend[-2] = '\0';
  7148. X      un_quote_string (nam1end + 4);
  7149. X      if (rename (nam1, nam1end + 4))
  7150. X        msg_perror ("Can't rename %s to %s", nam1, nam1end + 4);
  7151. X      else if (f_verbose)
  7152. X        msg ("Renamed %s to %s", nam1, nam1end + 4);
  7153. X    }
  7154. X#ifdef S_ISLNK
  7155. X      else if (!strncmp (ptr, "Symlink ", 8))
  7156. X    {
  7157. X      nam1 = ptr + 8;
  7158. X      nam1end = index (nam1, ' ');
  7159. X      while (strncmp (nam1end, " to ", 4))
  7160. X        {
  7161. X          nam1end++;
  7162. X          nam1end = index (nam1end, ' ');
  7163. X        }
  7164. X      *nam1end = '\0';
  7165. X      un_quote_string (nam1);
  7166. X      un_quote_string (nam1end + 4);
  7167. X      if (symlink (nam1, nam1end + 4) && (unlink (nam1end + 4) || symlink (nam1, nam1end + 4)))
  7168. X        msg_perror ("Can't symlink %s to %s", nam1, nam1end + 4);
  7169. X      else if (f_verbose)
  7170. X        msg ("Symlinkd %s to %s", nam1, nam1end + 4);
  7171. X    }
  7172. X#endif
  7173. X      else
  7174. X    msg ("Unknown demangling command %s", ptr);
  7175. X    }
  7176. X}
  7177. END_OF_FILE
  7178. if test 6635 -ne `wc -c <'mangle.c'`; then
  7179.     echo shar: \"'mangle.c'\" unpacked with wrong size!
  7180. fi
  7181. # end of 'mangle.c'
  7182. fi
  7183. if test -f 'version.c' -a "${1}" != "-c" ; then 
  7184.   echo shar: Will not clobber existing file \"'version.c'\"
  7185. else
  7186. echo shar: Extracting \"'version.c'\" \(50 characters\)
  7187. sed "s/^X//" >'version.c' <<'END_OF_FILE'
  7188. Xchar version_string[] = "GNU tar version 1.11.2";
  7189. END_OF_FILE
  7190. if test 50 -ne `wc -c <'version.c'`; then
  7191.     echo shar: \"'version.c'\" unpacked with wrong size!
  7192. fi
  7193. # end of 'version.c'
  7194. fi
  7195. if test -f 'list.c' -a "${1}" != "-c" ; then 
  7196.   echo shar: Will not clobber existing file \"'list.c'\"
  7197. else
  7198. echo shar: Extracting \"'list.c'\" \(20047 characters\)
  7199. sed "s/^X//" >'list.c' <<'END_OF_FILE'
  7200. X/* List a tar archive.
  7201. X   Copyright (C) 1988, 1992, 1993 Free Software Foundation
  7202. X
  7203. XThis file is part of GNU Tar.
  7204. X
  7205. XGNU Tar is free software; you can redistribute it and/or modify
  7206. Xit under the terms of the GNU General Public License as published by
  7207. Xthe Free Software Foundation; either version 2, or (at your option)
  7208. Xany later version.
  7209. X
  7210. XGNU Tar is distributed in the hope that it will be useful,
  7211. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  7212. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  7213. XGNU General Public License for more details.
  7214. X
  7215. XYou should have received a copy of the GNU General Public License
  7216. Xalong with GNU Tar; see the file COPYING.  If not, write to
  7217. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  7218. X
  7219. X/*
  7220. X * List a tar archive.
  7221. X *
  7222. X * Also includes support routines for reading a tar archive.
  7223. X *
  7224. X * this version written 26 Aug 1985 by John Gilmore (ihnp4!hoptoad!gnu).
  7225. X */
  7226. X
  7227. X#include <stdio.h>
  7228. X#include <ctype.h>
  7229. X#include <sys/types.h>
  7230. X#include <errno.h>
  7231. X#ifndef STDC_HEADERS
  7232. Xextern int errno;
  7233. X#endif
  7234. X#include <time.h>
  7235. X
  7236. X#ifdef BSD42
  7237. X#include <sys/file.h>
  7238. X#else
  7239. X#ifndef V7
  7240. X#include <fcntl.h>
  7241. X#endif
  7242. X#endif
  7243. X
  7244. X#define    isodigit(c)    ( ((c) >= '0') && ((c) <= '7') )
  7245. X
  7246. X#include "tar.h"
  7247. X#include "port.h"
  7248. X
  7249. Xextern FILE *msg_file;
  7250. X
  7251. Xlong from_oct ();        /* Decode octal number */
  7252. Xvoid demode ();            /* Print file mode */
  7253. Xvoid restore_saved_dir_info ();
  7254. XPTR ck_malloc ();
  7255. X
  7256. Xunion record *head;        /* Points to current archive header */
  7257. Xstruct stat hstat;        /* Stat struct corresponding */
  7258. Xint head_standard;        /* Tape header is in ANSI format */
  7259. X
  7260. Xint check_exclude ();
  7261. Xvoid close_archive ();
  7262. Xvoid decode_header ();
  7263. Xint findgid ();
  7264. Xint finduid ();
  7265. Xvoid name_gather ();
  7266. Xint name_match ();
  7267. Xvoid names_notfound ();
  7268. Xvoid open_archive ();
  7269. Xvoid print_header ();
  7270. Xint read_header ();
  7271. Xvoid saverec ();
  7272. Xvoid skip_file ();
  7273. Xvoid skip_extended_headers ();
  7274. X
  7275. Xextern char *quote_copy_string ();
  7276. X
  7277. X
  7278. X/*
  7279. X * Main loop for reading an archive.
  7280. X */
  7281. Xvoid
  7282. Xread_and (do_something)
  7283. X     void (*do_something) ();
  7284. X{
  7285. X  int status = 3;        /* Initial status at start of archive */
  7286. X  int prev_status;
  7287. X  extern time_t new_time;
  7288. X  char save_linkflag;
  7289. X
  7290. X  name_gather ();        /* Gather all the names */
  7291. X  open_archive (1);        /* Open for reading */
  7292. X
  7293. X  for (;;)
  7294. X    {
  7295. X      prev_status = status;
  7296. X      status = read_header ();
  7297. X      switch (status)
  7298. X    {
  7299. X
  7300. X    case 1:        /* Valid header */
  7301. X      /* We should decode next field (mode) first... */
  7302. X      /* Ensure incoming names are null terminated. */
  7303. X
  7304. X      if (!name_match (current_file_name)
  7305. X          || (f_new_files && hstat.st_mtime < new_time)
  7306. X          || (f_exclude && check_exclude (current_file_name)))
  7307. X        {
  7308. X
  7309. X          int isextended = 0;
  7310. X
  7311. X          if (head->header.linkflag == LF_VOLHDR
  7312. X          || head->header.linkflag == LF_MULTIVOL
  7313. X          || head->header.linkflag == LF_NAMES)
  7314. X        {
  7315. X          (*do_something) ();
  7316. X          continue;
  7317. X        }
  7318. X          if (f_show_omitted_dirs
  7319. X          && head->header.linkflag == LF_DIR)
  7320. X        msg ("Omitting %s\n", current_file_name);
  7321. X          /* Skip past it in the archive */
  7322. X          if (head->header.isextended)
  7323. X        isextended = 1;
  7324. X          save_linkflag = head->header.linkflag;
  7325. X          userec (head);
  7326. X          if (isextended)
  7327. X        {
  7328. X          /*                    register union record *exhdr;
  7329. X
  7330. X                    for (;;) {
  7331. X                        exhdr = findrec();
  7332. X                        if (!exhdr->ext_hdr.isextended) {
  7333. X                            userec(exhdr);
  7334. X                            break;
  7335. X                        }
  7336. X                    }
  7337. X                    userec(exhdr);*/
  7338. X          skip_extended_headers ();
  7339. X        }
  7340. X          /* Skip to the next header on the archive */
  7341. X          if (save_linkflag != LF_DIR)
  7342. X        skip_file ((long) hstat.st_size);
  7343. X          continue;
  7344. X
  7345. X        }
  7346. X
  7347. X      (*do_something) ();
  7348. X      continue;
  7349. X
  7350. X      /*
  7351. X             * If the previous header was good, tell them
  7352. X             * that we are skipping bad ones.
  7353. X             */
  7354. X    case 0:        /* Invalid header */
  7355. X      userec (head);
  7356. X      switch (prev_status)
  7357. X        {
  7358. X        case 3:        /* Error on first record */
  7359. X          msg ("Hmm, this doesn't look like a tar archive.");
  7360. X          /* FALL THRU */
  7361. X        case 2:        /* Error after record of zeroes */
  7362. X        case 1:        /* Error after header rec */
  7363. X          msg ("Skipping to next file header...");
  7364. X        case 0:        /* Error after error */
  7365. X          break;
  7366. X        }
  7367. X      continue;
  7368. X
  7369. X    case 2:        /* Record of zeroes */
  7370. X      userec (head);
  7371. X      status = prev_status;    /* If error after 0's */
  7372. X      if (f_ignorez)
  7373. X        continue;
  7374. X      /* FALL THRU */
  7375. X    case EOF:        /* End of archive */
  7376. X      break;
  7377. X    }
  7378. X      break;
  7379. X    };
  7380. X
  7381. X  restore_saved_dir_info ();
  7382. X  close_archive ();
  7383. X  names_notfound ();        /* Print names not found */
  7384. X}
  7385. X
  7386. X
  7387. X/*
  7388. X * Print a header record, based on tar options.
  7389. X */
  7390. Xvoid
  7391. Xlist_archive ()
  7392. X{
  7393. X  extern char *save_name;
  7394. X  int isextended = 0;        /* Flag to remember if head is extended */
  7395. X
  7396. X  /* Save the record */
  7397. X  saverec (&head);
  7398. X
  7399. X  /* Print the header record */
  7400. X  if (f_verbose)
  7401. X    {
  7402. X      if (f_verbose > 1)
  7403. X    decode_header (head, &hstat, &head_standard, 0);
  7404. X      print_header ();
  7405. X    }
  7406. X
  7407. X  if (f_gnudump && head->header.linkflag == LF_DUMPDIR)
  7408. X    {
  7409. X      size_t size, written, check;
  7410. X      char *data;
  7411. X      extern long save_totsize;
  7412. X      extern long save_sizeleft;
  7413. X
  7414. X      userec (head);
  7415. X      if (f_multivol)
  7416. X    {
  7417. X      save_name = current_file_name;
  7418. X      save_totsize = hstat.st_size;
  7419. X    }
  7420. X      for (size = hstat.st_size; size > 0; size -= written)
  7421. X    {
  7422. X      if (f_multivol)
  7423. X        save_sizeleft = size;
  7424. X      data = findrec ()->charptr;
  7425. X      if (data == NULL)
  7426. X        {
  7427. X          msg ("EOF in archive file?");
  7428. X          break;
  7429. X        }
  7430. X      written = endofrecs ()->charptr - data;
  7431. X      if (written > size)
  7432. X        written = size;
  7433. X      errno = 0;
  7434. X      check = fwrite (data, sizeof (char), written, msg_file);
  7435. X      userec ((union record *) (data + written - 1));
  7436. X      if (check != written)
  7437. X        {
  7438. X          msg_perror ("only wrote %ld of %ld bytes to file %s", check, written, current_file_name);
  7439. X          skip_file ((long) (size) - written);
  7440. X          break;
  7441. X        }
  7442. X    }
  7443. X      if (f_multivol)
  7444. X    save_name = 0;
  7445. X      saverec ((union record **) 0);    /* Unsave it */
  7446. X      fputc ('\n', msg_file);
  7447. X      fflush (msg_file);
  7448. X      return;
  7449. X
  7450. X    }
  7451. X  saverec ((union record **) 0);/* Unsave it */
  7452. X  /* Check to see if we have an extended header to skip over also */
  7453. X  if (head->header.isextended)
  7454. X    isextended = 1;
  7455. X
  7456. X  /* Skip past the header in the archive */
  7457. X  userec (head);
  7458. X
  7459. X  /*
  7460. X      * If we needed to skip any extended headers, do so now, by
  7461. X      * reading extended headers and skipping past them in the
  7462. X     * archive.
  7463. X     */
  7464. X  if (isextended)
  7465. X    {
  7466. X      /*        register union record *exhdr;
  7467. X
  7468. X        for (;;) {
  7469. X            exhdr = findrec();
  7470. X
  7471. X            if (!exhdr->ext_hdr.isextended) {
  7472. X                userec(exhdr);
  7473. X                break;
  7474. X            }
  7475. X            userec(exhdr);
  7476. X        }*/
  7477. X      skip_extended_headers ();
  7478. X    }
  7479. X
  7480. X  if (f_multivol)
  7481. X    save_name = current_file_name;
  7482. X  /* Skip to the next header on the archive */
  7483. X
  7484. X  skip_file ((long) hstat.st_size);
  7485. X
  7486. X  if (f_multivol)
  7487. X    save_name = 0;
  7488. X}
  7489. X
  7490. X
  7491. X/*
  7492. X * Read a record that's supposed to be a header record.
  7493. X * Return its address in "head", and if it is good, the file's
  7494. X * size in hstat.st_size.
  7495. X *
  7496. X * Return 1 for success, 0 if the checksum is bad, EOF on eof,
  7497. X * 2 for a record full of zeros (EOF marker).
  7498. X *
  7499. X * You must always userec(head) to skip past the header which this
  7500. X * routine reads.
  7501. X */
  7502. Xint
  7503. Xread_header ()
  7504. X{
  7505. X  register int i;
  7506. X  register long sum, signed_sum, recsum;
  7507. X  register char *p;
  7508. X  register union record *header;
  7509. X  long from_oct ();
  7510. X  char **longp;
  7511. X  char *bp, *data;
  7512. X  int size, written;
  7513. X  static char *next_long_name, *next_long_link;
  7514. X  char *name;
  7515. X
  7516. Xrecurse:
  7517. X
  7518. X  header = findrec ();
  7519. X  head = header;        /* This is our current header */
  7520. X  if (NULL == header)
  7521. X    return EOF;
  7522. X
  7523. X  recsum = from_oct (8, header->header.chksum);
  7524. X
  7525. X  sum = 0;
  7526. X  p = header->charptr;
  7527. X  for (i = sizeof (*header); --i >= 0;)
  7528. X    {
  7529. X      /*
  7530. X         * We can't use unsigned char here because of old compilers,
  7531. X         * e.g. V7.
  7532. X         */
  7533. X      signed_sum += *p;
  7534. X      sum += 0xFF & *p++;
  7535. X    }
  7536. X
  7537. X  /* Adjust checksum to count the "chksum" field as blanks. */
  7538. X  for (i = sizeof (header->header.chksum); --i >= 0;)
  7539. X    {
  7540. X      sum -= 0xFF & header->header.chksum[i];
  7541. X      signed_sum -= (char) header->header.chksum[i];
  7542. X    }
  7543. X  sum += ' ' * sizeof header->header.chksum;
  7544. X  signed_sum += ' ' * sizeof header->header.chksum;
  7545. X
  7546. X  if (sum == 8 * ' ')
  7547. X    {
  7548. X      /*
  7549. X         * This is a zeroed record...whole record is 0's except
  7550. X         * for the 8 blanks we faked for the checksum field.
  7551. X         */
  7552. X      return 2;
  7553. X    }
  7554. X
  7555. X  if (sum != recsum && signed_sum != recsum)
  7556. X    return 0;
  7557. X
  7558. X  /*
  7559. X     * Good record.  Decode file size and return.
  7560. X     */
  7561. X  if (header->header.linkflag == LF_LINK)
  7562. X    hstat.st_size = 0;        /* Links 0 size on tape */
  7563. X  else
  7564. X    hstat.st_size = from_oct (1 + 12, header->header.size);
  7565. X
  7566. X  header->header.arch_name[NAMSIZ - 1] = '\0';
  7567. X  if (header->header.linkflag == LF_LONGNAME
  7568. X      || header->header.linkflag == LF_LONGLINK)
  7569. X    {
  7570. X      longp = ((header->header.linkflag == LF_LONGNAME)
  7571. X           ? &next_long_name
  7572. X           : &next_long_link);
  7573. X
  7574. X      userec (header);
  7575. X      if (*longp)
  7576. X    free (*longp);
  7577. X      bp = *longp = (char *) ck_malloc (hstat.st_size);
  7578. X
  7579. X      for (size = hstat.st_size;
  7580. X       size > 0;
  7581. X       size -= written)
  7582. X    {
  7583. X      data = findrec ()->charptr;
  7584. X      if (data == NULL)
  7585. X        {
  7586. X          msg ("Unexpected EOF on archive file");
  7587. X          break;
  7588. X        }
  7589. X      written = endofrecs ()->charptr - data;
  7590. X      if (written > size)
  7591. X        written = size;
  7592. X
  7593. X      bcopy (data, bp, written);
  7594. X      bp += written;
  7595. X      userec ((union record *) (data + written - 1));
  7596. X    }
  7597. X      goto recurse;
  7598. X    }
  7599. X  else
  7600. X    {
  7601. X      name = (next_long_name
  7602. X          ? next_long_name
  7603. X          : head->header.arch_name);
  7604. X      if (current_file_name)
  7605. X    free (current_file_name);
  7606. X      current_file_name = ck_malloc (strlen (name) + 1);
  7607. X      strcpy (current_file_name, name);
  7608. X
  7609. X      name = (next_long_link
  7610. X          ? next_long_link
  7611. X          : head->header.arch_linkname);
  7612. X      if (current_link_name)
  7613. X    free (current_link_name);
  7614. X      current_link_name = ck_malloc (strlen (name) + 1);
  7615. X      strcpy (current_link_name, name);
  7616. X
  7617. X      next_long_link = next_long_name = 0;
  7618. X      return 1;
  7619. X    }
  7620. X}
  7621. X
  7622. X
  7623. X/*
  7624. X * Decode things from a file header record into a "struct stat".
  7625. X * Also set "*stdp" to !=0 or ==0 depending whether header record is "Unix
  7626. X * Standard" tar format or regular old tar format.
  7627. X *
  7628. X * read_header() has already decoded the checksum and length, so we don't.
  7629. X *
  7630. X * If wantug != 0, we want the uid/group info decoded from Unix Standard
  7631. X * tapes (for extraction).  If == 0, we are just printing anyway, so save time.
  7632. X *
  7633. X * decode_header should NOT be called twice for the same record, since the
  7634. X * two calls might use different "wantug" values and thus might end up with
  7635. X * different uid/gid for the two calls.  If anybody wants the uid/gid they
  7636. X * should decode it first, and other callers should decode it without uid/gid
  7637. X * before calling a routine, e.g. print_header, that assumes decoded data.
  7638. X */
  7639. Xvoid
  7640. Xdecode_header (header, st, stdp, wantug)
  7641. X     register union record *header;
  7642. X     register struct stat *st;
  7643. X     int *stdp;
  7644. X     int wantug;
  7645. X{
  7646. X  long from_oct ();
  7647. X
  7648. X  st->st_mode = from_oct (8, header->header.mode);
  7649. X  st->st_mode &= 07777;
  7650. X  st->st_mtime = from_oct (1 + 12, header->header.mtime);
  7651. X  if (f_gnudump)
  7652. X    {
  7653. X      st->st_atime = from_oct (1 + 12, header->header.atime);
  7654. X      st->st_ctime = from_oct (1 + 12, header->header.ctime);
  7655. X    }
  7656. X
  7657. X  if (0 == strcmp (header->header.magic, TMAGIC))
  7658. X    {
  7659. X      /* Unix Standard tar archive */
  7660. X      *stdp = 1;
  7661. X      if (wantug)
  7662. X    {
  7663. X#ifdef NONAMES
  7664. X      st->st_uid = from_oct (8, header->header.uid);
  7665. X      st->st_gid = from_oct (8, header->header.gid);
  7666. X#else
  7667. X      st->st_uid =
  7668. X        (*header->header.uname
  7669. X         ? finduid (header->header.uname)
  7670. X         : from_oct (8, header->header.uid));
  7671. X      st->st_gid =
  7672. X        (*header->header.gname
  7673. X         ? findgid (header->header.gname)
  7674. X         : from_oct (8, header->header.gid));
  7675. X#endif
  7676. X    }
  7677. X#if defined(S_IFBLK) || defined(S_IFCHR)
  7678. X      switch (header->header.linkflag)
  7679. X    {
  7680. X    case LF_BLK:
  7681. X    case LF_CHR:
  7682. X      st->st_rdev = makedev (from_oct (8, header->header.devmajor),
  7683. X                 from_oct (8, header->header.devminor));
  7684. X    }
  7685. X#endif
  7686. X    }
  7687. X  else
  7688. X    {
  7689. X      /* Old fashioned tar archive */
  7690. X      *stdp = 0;
  7691. X      st->st_uid = from_oct (8, header->header.uid);
  7692. X      st->st_gid = from_oct (8, header->header.gid);
  7693. X      st->st_rdev = 0;
  7694. X    }
  7695. X}
  7696. X
  7697. X
  7698. X/*
  7699. X * Quick and dirty octal conversion.
  7700. X *
  7701. X * Result is -1 if the field is invalid (all blank, or nonoctal).
  7702. X */
  7703. Xlong
  7704. Xfrom_oct (digs, where)
  7705. X     register int digs;
  7706. X     register char *where;
  7707. X{
  7708. X  register long value;
  7709. X
  7710. X  while (isspace (*where))
  7711. X    {                /* Skip spaces */
  7712. X      where++;
  7713. X      if (--digs <= 0)
  7714. X    return -1;        /* All blank field */
  7715. X    }
  7716. X  value = 0;
  7717. X  while (digs > 0 && isodigit (*where))
  7718. X    {                /* Scan til nonoctal */
  7719. X      value = (value << 3) | (*where++ - '0');
  7720. X      --digs;
  7721. X    }
  7722. X
  7723. X  if (digs > 0 && *where && !isspace (*where))
  7724. X    return -1;            /* Ended on non-space/nul */
  7725. X
  7726. X  return value;
  7727. X}
  7728. X
  7729. X
  7730. X/*
  7731. X * Actually print it.
  7732. X *
  7733. X * Plain and fancy file header block logging.
  7734. X * Non-verbose just prints the name, e.g. for "tar t" or "tar x".
  7735. X * This should just contain file names, so it can be fed back into tar
  7736. X * with xargs or the "-T" option.  The verbose option can give a bunch
  7737. X * of info, one line per file.  I doubt anybody tries to parse its
  7738. X * format, or if they do, they shouldn't.  Unix tar is pretty random here
  7739. X * anyway.
  7740. X *
  7741. X * Note that print_header uses the globals <head>, <hstat>, and
  7742. X * <head_standard>, which must be set up in advance.  This is not very clean
  7743. X * and should be cleaned up.  FIXME.
  7744. X */
  7745. X#define    UGSWIDTH    18    /* min width of User, group, size */
  7746. X/* UGSWIDTH of 18 means that with user and group names <= 8 chars the columns
  7747. X   never shift during the listing.  */
  7748. X#define    DATEWIDTH    19    /* Last mod date */
  7749. Xstatic int ugswidth = UGSWIDTH;    /* Max width encountered so far */
  7750. X
  7751. Xvoid
  7752. Xprint_header ()
  7753. X{
  7754. X  char modes[11];
  7755. X  char *timestamp;
  7756. X  char uform[11], gform[11];    /* These hold formatted ints */
  7757. X  char *user, *group;
  7758. X  char size[24];        /* Holds a formatted long or maj, min */
  7759. X  time_t longie;        /* To make ctime() call portable */
  7760. X  int pad;
  7761. X  char *name;
  7762. X  extern long baserec;
  7763. X
  7764. X  if (f_sayblock)
  7765. X    fprintf (msg_file, "rec %10d: ", baserec + (ar_record - ar_block));
  7766. X  /* annofile(msg_file, (char *)NULL); */
  7767. X
  7768. X  if (f_verbose <= 1)
  7769. X    {
  7770. X      /* Just the fax, mam. */
  7771. X      char *name;
  7772. X
  7773. X      name = quote_copy_string (current_file_name);
  7774. X      if (name == 0)
  7775. X    name = current_file_name;
  7776. X      fprintf (msg_file, "%s\n", name);
  7777. X      if (name != current_file_name)
  7778. X    free (name);
  7779. X    }
  7780. X  else
  7781. X    {
  7782. X      /* File type and modes */
  7783. X      modes[0] = '?';
  7784. X      switch (head->header.linkflag)
  7785. X    {
  7786. X    case LF_VOLHDR:
  7787. X      modes[0] = 'V';
  7788. X      break;
  7789. X
  7790. X    case LF_MULTIVOL:
  7791. X      modes[0] = 'M';
  7792. X      break;
  7793. X
  7794. X    case LF_NAMES:
  7795. X      modes[0] = 'N';
  7796. X      break;
  7797. X
  7798. X    case LF_LONGNAME:
  7799. X    case LF_LONGLINK:
  7800. X      msg ("Visible longname error\n");
  7801. X      break;
  7802. X
  7803. X    case LF_SPARSE:
  7804. X    case LF_NORMAL:
  7805. X    case LF_OLDNORMAL:
  7806. X    case LF_LINK:
  7807. X      modes[0] = '-';
  7808. X      if ('/' == current_file_name[strlen (current_file_name) - 1])
  7809. X        modes[0] = 'd';
  7810. X      break;
  7811. X    case LF_DUMPDIR:
  7812. X      modes[0] = 'd';
  7813. X      break;
  7814. X    case LF_DIR:
  7815. X      modes[0] = 'd';
  7816. X      break;
  7817. X    case LF_SYMLINK:
  7818. X      modes[0] = 'l';
  7819. X      break;
  7820. X    case LF_BLK:
  7821. X      modes[0] = 'b';
  7822. X      break;
  7823. X    case LF_CHR:
  7824. X      modes[0] = 'c';
  7825. X      break;
  7826. X    case LF_FIFO:
  7827. X      modes[0] = 'p';
  7828. X      break;
  7829. X    case LF_CONTIG:
  7830. X      modes[0] = 'C';
  7831. X      break;
  7832. X    }
  7833. X
  7834. X      demode ((unsigned) hstat.st_mode, modes + 1);
  7835. X
  7836. X      /* Timestamp */
  7837. X      longie = hstat.st_mtime;
  7838. X      timestamp = ctime (&longie);
  7839. X      timestamp[16] = '\0';
  7840. X      timestamp[24] = '\0';
  7841. X
  7842. X      /* User and group names */
  7843. X      if (*head->header.uname && head_standard)
  7844. X    {
  7845. X      user = head->header.uname;
  7846. X    }
  7847. X      else
  7848. X    {
  7849. X      user = uform;
  7850. X      (void) sprintf (uform, "%d",
  7851. X              from_oct (8, head->header.uid));
  7852. X    }
  7853. X      if (*head->header.gname && head_standard)
  7854. X    {
  7855. X      group = head->header.gname;
  7856. X    }
  7857. X      else
  7858. X    {
  7859. X      group = gform;
  7860. X      (void) sprintf (gform, "%d",
  7861. X              from_oct (8, head->header.gid));
  7862. X    }
  7863. X
  7864. X      /* Format the file size or major/minor device numbers */
  7865. X      switch (head->header.linkflag)
  7866. X    {
  7867. X#if defined(S_IFBLK) || defined(S_IFCHR)
  7868. X    case LF_CHR:
  7869. X    case LF_BLK:
  7870. X      (void) sprintf (size, "%d,%d",
  7871. X              major (hstat.st_rdev),
  7872. X              minor (hstat.st_rdev));
  7873. X      break;
  7874. X#endif
  7875. X    case LF_SPARSE:
  7876. X      (void) sprintf (size, "%ld",
  7877. X              from_oct (1 + 12, head->header.realsize));
  7878. X      break;
  7879. X    default:
  7880. X      (void) sprintf (size, "%ld", (long) hstat.st_size);
  7881. X    }
  7882. X
  7883. X      /* Figure out padding and print the whole line. */
  7884. X      pad = strlen (user) + strlen (group) + strlen (size) + 1;
  7885. X      if (pad > ugswidth)
  7886. X    ugswidth = pad;
  7887. X
  7888. X      name = quote_copy_string (current_file_name);
  7889. X      if (!name)
  7890. X    name = current_file_name;
  7891. X      fprintf (msg_file, "%s %s/%s %*s%s %s %s %s",
  7892. X           modes,
  7893. X           user,
  7894. X           group,
  7895. X           ugswidth - pad,
  7896. X           "",
  7897. X           size,
  7898. X           timestamp + 4, timestamp + 20,
  7899. X           name);
  7900. X
  7901. X      if (name != current_file_name)
  7902. X    free (name);
  7903. X      switch (head->header.linkflag)
  7904. X    {
  7905. X    case LF_SYMLINK:
  7906. X      name = quote_copy_string (current_link_name);
  7907. X      if (!name)
  7908. X        name = current_link_name;
  7909. X      fprintf (msg_file, " -> %s\n", name);
  7910. X      if (name != current_link_name)
  7911. X        free (name);
  7912. X      break;
  7913. X
  7914. X    case LF_LINK:
  7915. X      name = quote_copy_string (current_link_name);
  7916. X      if (!name)
  7917. X        name = current_link_name;
  7918. X      fprintf (msg_file, " link to %s\n", current_link_name);
  7919. X      if (name != current_link_name)
  7920. X        free (name);
  7921. X      break;
  7922. X
  7923. X    default:
  7924. X      fprintf (msg_file, " unknown file type '%c'\n",
  7925. X           head->header.linkflag);
  7926. X      break;
  7927. X
  7928. X    case LF_OLDNORMAL:
  7929. X    case LF_NORMAL:
  7930. X    case LF_SPARSE:
  7931. X    case LF_CHR:
  7932. X    case LF_BLK:
  7933. X    case LF_DIR:
  7934. X    case LF_FIFO:
  7935. X    case LF_CONTIG:
  7936. X    case LF_DUMPDIR:
  7937. X      putc ('\n', msg_file);
  7938. X      break;
  7939. X
  7940. X    case LF_VOLHDR:
  7941. X      fprintf (msg_file, "--Volume Header--\n");
  7942. X      break;
  7943. X
  7944. X    case LF_MULTIVOL:
  7945. X      fprintf (msg_file, "--Continued at byte %ld--\n", from_oct (1 + 12, head->header.offset));
  7946. X      break;
  7947. X
  7948. X    case LF_NAMES:
  7949. X      fprintf (msg_file, "--Mangled file names--\n");
  7950. X      break;
  7951. X    }
  7952. X    }
  7953. X  fflush (msg_file);
  7954. X}
  7955. X
  7956. X/*
  7957. X * Print a similar line when we make a directory automatically.
  7958. X */
  7959. Xvoid
  7960. Xpr_mkdir (pathname, length, mode)
  7961. X     char *pathname;
  7962. X     int length;
  7963. X     int mode;
  7964. X{
  7965. X  char modes[11];
  7966. X  char *name;
  7967. X  extern long baserec;
  7968. X
  7969. X  if (f_verbose > 1)
  7970. X    {
  7971. X      /* File type and modes */
  7972. X      modes[0] = 'd';
  7973. X      demode ((unsigned) mode, modes + 1);
  7974. X
  7975. X      if (f_sayblock)
  7976. X    fprintf (msg_file, "rec %10d: ", baserec + (ar_record - ar_block));
  7977. X      /* annofile(msg_file, (char *)NULL); */
  7978. X      name = quote_copy_string (pathname);
  7979. X      if (!name)
  7980. X    name = pathname;
  7981. X      fprintf (msg_file, "%s %*s %.*s\n",
  7982. X           modes,
  7983. X           ugswidth + DATEWIDTH,
  7984. X           "Creating directory:",
  7985. X           length,
  7986. X           pathname);
  7987. X      if (name != pathname)
  7988. X    free (name);
  7989. X    }
  7990. X}
  7991. X
  7992. X
  7993. X/*
  7994. X * Skip over <size> bytes of data in records in the archive.
  7995. X */
  7996. Xvoid
  7997. Xskip_file (size)
  7998. X     register long size;
  7999. X{
  8000. X  union record *x;
  8001. X  extern long save_totsize;
  8002. X  extern long save_sizeleft;
  8003. X
  8004. X  if (f_multivol)
  8005. X    {
  8006. X      save_totsize = size;
  8007. X      save_sizeleft = size;
  8008. X    }
  8009. X
  8010. X  while (size > 0)
  8011. X    {
  8012. X      x = findrec ();
  8013. X      if (x == NULL)
  8014. X    {            /* Check it... */
  8015. X      msg ("Unexpected EOF on archive file");
  8016. X      exit (EX_BADARCH);
  8017. X    }
  8018. X      userec (x);
  8019. X      size -= RECORDSIZE;
  8020. X      if (f_multivol)
  8021. X    save_sizeleft -= RECORDSIZE;
  8022. X    }
  8023. X}
  8024. X
  8025. Xvoid
  8026. Xskip_extended_headers ()
  8027. X{
  8028. X  register union record *exhdr;
  8029. X
  8030. X  for (;;)
  8031. X    {
  8032. X      exhdr = findrec ();
  8033. X      if (!exhdr->ext_hdr.isextended)
  8034. X    {
  8035. X      userec (exhdr);
  8036. X      break;
  8037. X    }
  8038. X      userec (exhdr);
  8039. X    }
  8040. X}
  8041. X
  8042. X/*
  8043. X * Decode the mode string from a stat entry into a 9-char string and a null.
  8044. X */
  8045. Xvoid
  8046. Xdemode (mode, string)
  8047. X     register unsigned mode;
  8048. X     register char *string;
  8049. X{
  8050. X  register unsigned mask;
  8051. X  register char *rwx = "rwxrwxrwx";
  8052. X
  8053. X  for (mask = 0400; mask != 0; mask >>= 1)
  8054. X    {
  8055. X      if (mode & mask)
  8056. X    *string++ = *rwx++;
  8057. X      else
  8058. X    {
  8059. X      *string++ = '-';
  8060. X      rwx++;
  8061. X    }
  8062. X    }
  8063. X
  8064. X  if (mode & S_ISUID)
  8065. X    if (string[-7] == 'x')
  8066. X      string[-7] = 's';
  8067. X    else
  8068. X      string[-7] = 'S';
  8069. X  if (mode & S_ISGID)
  8070. X    if (string[-4] == 'x')
  8071. X      string[-4] = 's';
  8072. X    else
  8073. X      string[-4] = 'S';
  8074. X  if (mode & S_ISVTX)
  8075. X    if (string[-1] == 'x')
  8076. X      string[-1] = 't';
  8077. X    else
  8078. X      string[-1] = 'T';
  8079. X  *string = '\0';
  8080. X}
  8081. END_OF_FILE
  8082. if test 20047 -ne `wc -c <'list.c'`; then
  8083.     echo shar: \"'list.c'\" unpacked with wrong size!
  8084. fi
  8085. # end of 'list.c'
  8086. fi
  8087. if test -f 'names.c' -a "${1}" != "-c" ; then 
  8088.   echo shar: Will not clobber existing file \"'names.c'\"
  8089. else
  8090. echo shar: Extracting \"'names.c'\" \(3302 characters\)
  8091. sed "s/^X//" >'names.c' <<'END_OF_FILE'
  8092. X/* Look up user and/or group names.
  8093. X   Copyright (C) 1988, 1992 Free Software Foundation
  8094. X
  8095. XThis file is part of GNU Tar.
  8096. X
  8097. XGNU Tar is free software; you can redistribute it and/or modify
  8098. Xit under the terms of the GNU General Public License as published by
  8099. Xthe Free Software Foundation; either version 2, or (at your option)
  8100. Xany later version.
  8101. X
  8102. XGNU Tar is distributed in the hope that it will be useful,
  8103. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  8104. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  8105. XGNU General Public License for more details.
  8106. X
  8107. XYou should have received a copy of the GNU General Public License
  8108. Xalong with GNU Tar; see the file COPYING.  If not, write to
  8109. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  8110. X
  8111. X/*
  8112. X * Look up user and/or group names.
  8113. X *
  8114. X * This file should be modified for non-unix systems to do something
  8115. X * reasonable.
  8116. X */
  8117. X
  8118. X#include <sys/types.h>
  8119. X#include "tar.h"
  8120. X#include "port.h"
  8121. X
  8122. X#ifndef NONAMES
  8123. X/* Whole module goes away if NONAMES defined.  Otherwise... */
  8124. X#include <stdio.h>
  8125. X#include <pwd.h>
  8126. X#include <grp.h>
  8127. X
  8128. Xstatic int saveuid = -993;
  8129. Xstatic char saveuname[TUNMLEN];
  8130. Xstatic int my_uid = -993;
  8131. X
  8132. Xstatic int savegid = -993;
  8133. Xstatic char savegname[TGNMLEN];
  8134. Xstatic int my_gid = -993;
  8135. X
  8136. X#define myuid    ( my_uid < 0? (my_uid = getuid()): my_uid )
  8137. X#define    mygid    ( my_gid < 0? (my_gid = getgid()): my_gid )
  8138. X
  8139. X/*
  8140. X * Look up a user or group name from a uid/gid, maintaining a cache.
  8141. X * FIXME, for now it's a one-entry cache.
  8142. X * FIXME2, the "-993" is to reduce the chance of a hit on the first lookup.
  8143. X *
  8144. X * This is ifdef'd because on Suns, it drags in about 38K of "yellow
  8145. X * pages" code, roughly doubling the program size.  Thanks guys.
  8146. X */
  8147. Xvoid
  8148. Xfinduname (uname, uid)
  8149. X     char uname[TUNMLEN];
  8150. X     int uid;
  8151. X{
  8152. X  struct passwd *pw;
  8153. X#ifndef HAVE_GETPWUID
  8154. X  extern struct passwd *getpwuid ();
  8155. X#endif
  8156. X
  8157. X  if (uid != saveuid)
  8158. X    {
  8159. X      saveuid = uid;
  8160. X      saveuname[0] = '\0';
  8161. X      pw = getpwuid (uid);
  8162. X      if (pw)
  8163. X    strncpy (saveuname, pw->pw_name, TUNMLEN);
  8164. X    }
  8165. X  strncpy (uname, saveuname, TUNMLEN);
  8166. X}
  8167. X
  8168. Xint
  8169. Xfinduid (uname)
  8170. X     char uname[TUNMLEN];
  8171. X{
  8172. X  struct passwd *pw;
  8173. X  extern struct passwd *getpwnam ();
  8174. X
  8175. X  if (uname[0] != saveuname[0]    /* Quick test w/o proc call */
  8176. X      || 0 != strncmp (uname, saveuname, TUNMLEN))
  8177. X    {
  8178. X      strncpy (saveuname, uname, TUNMLEN);
  8179. X      pw = getpwnam (uname);
  8180. X      if (pw)
  8181. X    {
  8182. X      saveuid = pw->pw_uid;
  8183. X    }
  8184. X      else
  8185. X    {
  8186. X      saveuid = myuid;
  8187. X    }
  8188. X    }
  8189. X  return saveuid;
  8190. X}
  8191. X
  8192. X
  8193. Xvoid
  8194. Xfindgname (gname, gid)
  8195. X     char gname[TGNMLEN];
  8196. X     int gid;
  8197. X{
  8198. X  struct group *gr;
  8199. X#ifndef HAVE_GETGRGID
  8200. X  extern struct group *getgrgid ();
  8201. X#endif
  8202. X
  8203. X  if (gid != savegid)
  8204. X    {
  8205. X      savegid = gid;
  8206. X      savegname[0] = '\0';
  8207. X      (void) setgrent ();
  8208. X      gr = getgrgid (gid);
  8209. X      if (gr)
  8210. X    strncpy (savegname, gr->gr_name, TGNMLEN);
  8211. X    }
  8212. X  (void) strncpy (gname, savegname, TGNMLEN);
  8213. X}
  8214. X
  8215. X
  8216. Xint
  8217. Xfindgid (gname)
  8218. X     char gname[TUNMLEN];
  8219. X{
  8220. X  struct group *gr;
  8221. X  extern struct group *getgrnam ();
  8222. X
  8223. X  if (gname[0] != savegname[0]    /* Quick test w/o proc call */
  8224. X      || 0 != strncmp (gname, savegname, TUNMLEN))
  8225. X    {
  8226. X      strncpy (savegname, gname, TUNMLEN);
  8227. X      gr = getgrnam (gname);
  8228. X      if (gr)
  8229. X    {
  8230. X      savegid = gr->gr_gid;
  8231. X    }
  8232. X      else
  8233. X    {
  8234. X      savegid = mygid;
  8235. X    }
  8236. X    }
  8237. X  return savegid;
  8238. X}
  8239. X
  8240. X#endif
  8241. END_OF_FILE
  8242. if test 3302 -ne `wc -c <'names.c'`; then
  8243.     echo shar: \"'names.c'\" unpacked with wrong size!
  8244. fi
  8245. # end of 'names.c'
  8246. fi
  8247. if test -f 'diffarch.c' -a "${1}" != "-c" ; then 
  8248.   echo shar: Will not clobber existing file \"'diffarch.c'\"
  8249. else
  8250. echo shar: Extracting \"'diffarch.c'\" \(16692 characters\)
  8251. sed "s/^X//" >'diffarch.c' <<'END_OF_FILE'
  8252. X/* Diff files from a tar archive.
  8253. X   Copyright (C) 1988, 1992, 1993 Free Software Foundation
  8254. X
  8255. XThis file is part of GNU Tar.
  8256. X
  8257. XGNU Tar is free software; you can redistribute it and/or modify
  8258. Xit under the terms of the GNU General Public License as published by
  8259. Xthe Free Software Foundation; either version 2, or (at your option)
  8260. Xany later version.
  8261. X
  8262. XGNU Tar is distributed in the hope that it will be useful,
  8263. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  8264. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  8265. XGNU General Public License for more details.
  8266. X
  8267. XYou should have received a copy of the GNU General Public License
  8268. Xalong with GNU Tar; see the file COPYING.  If not, write to
  8269. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  8270. X
  8271. X/*
  8272. X * Diff files from a tar archive.
  8273. X *
  8274. X * Written 30 April 1987 by John Gilmore, ihnp4!hoptoad!gnu.
  8275. X */
  8276. X
  8277. X#include <stdio.h>
  8278. X#include <errno.h>
  8279. X#ifndef STDC_HEADERS
  8280. Xextern int errno;
  8281. X#endif
  8282. X#include <sys/types.h>
  8283. X
  8284. X#ifdef BSD42
  8285. X#include <sys/file.h>
  8286. X#else
  8287. X#ifndef V7
  8288. X#include <fcntl.h>
  8289. X#endif
  8290. X#endif
  8291. X
  8292. X#ifdef HAVE_SYS_MTIO_H
  8293. X#include <sys/ioctl.h>
  8294. X#include <sys/mtio.h>
  8295. X#endif
  8296. X
  8297. X#include "tar.h"
  8298. X#include "port.h"
  8299. X#include "rmt.h"
  8300. X
  8301. X#ifndef S_ISLNK
  8302. X#define lstat stat
  8303. X#endif
  8304. X
  8305. Xextern void *valloc ();
  8306. X
  8307. Xextern union record *head;    /* Points to current tape header */
  8308. Xextern struct stat hstat;    /* Stat struct corresponding */
  8309. Xextern int head_standard;    /* Tape header is in ANSI format */
  8310. X
  8311. Xvoid decode_header ();
  8312. Xvoid diff_sparse_files ();
  8313. Xvoid fill_in_sparse_array ();
  8314. Xvoid fl_read ();
  8315. Xlong from_oct ();
  8316. Xint do_stat ();
  8317. Xextern void print_header ();
  8318. Xint read_header ();
  8319. Xvoid saverec ();
  8320. Xvoid sigh ();
  8321. Xextern void skip_file ();
  8322. Xextern void skip_extended_headers ();
  8323. Xint wantbytes ();
  8324. X
  8325. Xextern FILE *msg_file;
  8326. X
  8327. Xint now_verifying = 0;        /* Are we verifying at the moment? */
  8328. X
  8329. Xint diff_fd;            /* Descriptor of file we're diffing */
  8330. X
  8331. Xchar *diff_buf = 0;        /* Pointer to area for reading
  8332. X                       file contents into */
  8333. X
  8334. Xchar *diff_dir;            /* Directory contents for LF_DUMPDIR */
  8335. X
  8336. Xint different = 0;
  8337. X
  8338. X/*struct sp_array *sparsearray;
  8339. Xint         sp_ar_size = 10;*/
  8340. X/*
  8341. X * Initialize for a diff operation
  8342. X */
  8343. Xvoid
  8344. Xdiff_init ()
  8345. X{
  8346. X  /*NOSTRICT*/
  8347. X  diff_buf = (char *) valloc ((unsigned) blocksize);
  8348. X  if (!diff_buf)
  8349. X    {
  8350. X      msg ("could not allocate memory for diff buffer of %d bytes",
  8351. X       blocksize);
  8352. X      exit (EX_ARGSBAD);
  8353. X    }
  8354. X}
  8355. X
  8356. X/*
  8357. X * Diff a file against the archive.
  8358. X */
  8359. Xvoid
  8360. Xdiff_archive ()
  8361. X{
  8362. X  register char *data;
  8363. X  int check, namelen;
  8364. X  int err;
  8365. X  long offset;
  8366. X  struct stat filestat;
  8367. X  int compare_chunk ();
  8368. X  int compare_dir ();
  8369. X  int no_op ();
  8370. X#ifndef __MSDOS__
  8371. X  dev_t dev;
  8372. X  ino_t ino;
  8373. X#endif
  8374. X  char *get_dir_contents ();
  8375. X  long from_oct ();
  8376. X
  8377. X  errno = EPIPE;        /* FIXME, remove perrors */
  8378. X
  8379. X  saverec (&head);        /* Make sure it sticks around */
  8380. X  userec (head);        /* And go past it in the archive */
  8381. X  decode_header (head, &hstat, &head_standard, 1);    /* Snarf fields */
  8382. X
  8383. X  /* Print the record from 'head' and 'hstat' */
  8384. X  if (f_verbose)
  8385. X    {
  8386. X      if (now_verifying)
  8387. X    fprintf (msg_file, "Verify ");
  8388. X      print_header ();
  8389. X    }
  8390. X
  8391. X  switch (head->header.linkflag)
  8392. X    {
  8393. X
  8394. X    default:
  8395. X      msg ("Unknown file type '%c' for %s, diffed as normal file",
  8396. X       head->header.linkflag, current_file_name);
  8397. X      /* FALL THRU */
  8398. X
  8399. X    case LF_OLDNORMAL:
  8400. X    case LF_NORMAL:
  8401. X    case LF_SPARSE:
  8402. X    case LF_CONTIG:
  8403. X      /*
  8404. X         * Appears to be a file.
  8405. X         * See if it's really a directory.
  8406. X         */
  8407. X      namelen = strlen (current_file_name) - 1;
  8408. X      if (current_file_name[namelen] == '/')
  8409. X    goto really_dir;
  8410. X
  8411. X
  8412. X      if (do_stat (&filestat))
  8413. X    {
  8414. X      if (head->header.isextended)
  8415. X        skip_extended_headers ();
  8416. X      skip_file ((long) hstat.st_size);
  8417. X      different++;
  8418. X      goto quit;
  8419. X    }
  8420. X
  8421. X      if (!S_ISREG (filestat.st_mode))
  8422. X    {
  8423. X      fprintf (msg_file, "%s: not a regular file\n",
  8424. X           current_file_name);
  8425. X      skip_file ((long) hstat.st_size);
  8426. X      different++;
  8427. X      goto quit;
  8428. X    }
  8429. X
  8430. X      filestat.st_mode &= 07777;
  8431. X      if (filestat.st_mode != hstat.st_mode)
  8432. X    sigh ("mode");
  8433. X      if (filestat.st_uid != hstat.st_uid)
  8434. X    sigh ("uid");
  8435. X      if (filestat.st_gid != hstat.st_gid)
  8436. X    sigh ("gid");
  8437. X      if (filestat.st_mtime != hstat.st_mtime)
  8438. X    sigh ("mod time");
  8439. X      if (head->header.linkflag != LF_SPARSE &&
  8440. X      filestat.st_size != hstat.st_size)
  8441. X    {
  8442. X      sigh ("size");
  8443. X      skip_file ((long) hstat.st_size);
  8444. X      goto quit;
  8445. X    }
  8446. X
  8447. X      diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
  8448. X
  8449. X      if (diff_fd < 0 && !f_absolute_paths)
  8450. X    {
  8451. X      char tmpbuf[NAMSIZ + 2];
  8452. X
  8453. X      tmpbuf[0] = '/';
  8454. X      strcpy (&tmpbuf[1], current_file_name);
  8455. X      diff_fd = open (tmpbuf, O_NDELAY | O_RDONLY);
  8456. X    }
  8457. X      if (diff_fd < 0)
  8458. X    {
  8459. X      msg_perror ("cannot open %s", current_file_name);
  8460. X      if (head->header.isextended)
  8461. X        skip_extended_headers ();
  8462. X      skip_file ((long) hstat.st_size);
  8463. X      different++;
  8464. X      goto quit;
  8465. X    }
  8466. X      /*
  8467. X         * Need to treat sparse files completely differently here.
  8468. X         */
  8469. X      if (head->header.linkflag == LF_SPARSE)
  8470. X    diff_sparse_files (hstat.st_size);
  8471. X      else
  8472. X    wantbytes ((long) (hstat.st_size), compare_chunk);
  8473. X
  8474. X      check = close (diff_fd);
  8475. X      if (check < 0)
  8476. X    msg_perror ("Error while closing %s", current_file_name);
  8477. X
  8478. X    quit:
  8479. X      break;
  8480. X
  8481. X#ifndef __MSDOS__
  8482. X    case LF_LINK:
  8483. X      if (do_stat (&filestat))
  8484. X    break;
  8485. X      dev = filestat.st_dev;
  8486. X      ino = filestat.st_ino;
  8487. X      err = stat (current_link_name, &filestat);
  8488. X      if (err < 0)
  8489. X    {
  8490. X      if (errno == ENOENT)
  8491. X        {
  8492. X          fprintf (msg_file, "%s: does not exist\n", current_file_name);
  8493. X        }
  8494. X      else
  8495. X        {
  8496. X          msg_perror ("cannot stat file %s", current_file_name);
  8497. X        }
  8498. X      different++;
  8499. X      break;
  8500. X    }
  8501. X      if (filestat.st_dev != dev || filestat.st_ino != ino)
  8502. X    {
  8503. X      fprintf (msg_file, "%s not linked to %s\n", current_file_name, current_link_name);
  8504. X      break;
  8505. X    }
  8506. X      break;
  8507. X#endif
  8508. X
  8509. X#ifdef S_ISLNK
  8510. X    case LF_SYMLINK:
  8511. X      {
  8512. X    char linkbuf[NAMSIZ + 3];
  8513. X    check = readlink (current_file_name, linkbuf,
  8514. X              (sizeof linkbuf) - 1);
  8515. X
  8516. X    if (check < 0)
  8517. X      {
  8518. X        if (errno == ENOENT)
  8519. X          {
  8520. X        fprintf (msg_file,
  8521. X             "%s: no such file or directory\n",
  8522. X             current_file_name);
  8523. X          }
  8524. X        else
  8525. X          {
  8526. X        msg_perror ("cannot read link %s", current_file_name);
  8527. X          }
  8528. X        different++;
  8529. X        break;
  8530. X      }
  8531. X
  8532. X    linkbuf[check] = '\0';    /* Null-terminate it */
  8533. X    if (strncmp (current_link_name, linkbuf, check) != 0)
  8534. X      {
  8535. X        fprintf (msg_file, "%s: symlink differs\n",
  8536. X             current_link_name);
  8537. X        different++;
  8538. X      }
  8539. X      }
  8540. X      break;
  8541. X#endif
  8542. X
  8543. X#ifdef S_IFCHR
  8544. X    case LF_CHR:
  8545. X      hstat.st_mode |= S_IFCHR;
  8546. X      goto check_node;
  8547. X#endif
  8548. X
  8549. X#ifdef S_IFBLK
  8550. X      /* If local system doesn't support block devices, use default case */
  8551. X    case LF_BLK:
  8552. X      hstat.st_mode |= S_IFBLK;
  8553. X      goto check_node;
  8554. X#endif
  8555. X
  8556. X#ifdef S_ISFIFO
  8557. X      /* If local system doesn't support FIFOs, use default case */
  8558. X    case LF_FIFO:
  8559. X#ifdef S_IFIFO
  8560. X      hstat.st_mode |= S_IFIFO;
  8561. X#endif
  8562. X      hstat.st_rdev = 0;    /* FIXME, do we need this? */
  8563. X      goto check_node;
  8564. X#endif
  8565. X
  8566. X    check_node:
  8567. X      /* FIXME, deal with umask */
  8568. X      if (do_stat (&filestat))
  8569. X    break;
  8570. X      if (hstat.st_rdev != filestat.st_rdev)
  8571. X    {
  8572. X      fprintf (msg_file, "%s: device numbers changed\n", current_file_name);
  8573. X      different++;
  8574. X      break;
  8575. X    }
  8576. X#ifdef S_IFMT
  8577. X      if (hstat.st_mode != filestat.st_mode)
  8578. X#else /* POSIX lossage */
  8579. X      if ((hstat.st_mode & 07777) != (filestat.st_mode & 07777))
  8580. X#endif
  8581. X    {
  8582. X      fprintf (msg_file, "%s: mode or device-type changed\n", current_file_name);
  8583. X      different++;
  8584. X      break;
  8585. X    }
  8586. X      break;
  8587. X
  8588. X    case LF_DUMPDIR:
  8589. X      data = diff_dir = get_dir_contents (current_file_name, 0);
  8590. X      if (data)
  8591. X    {
  8592. X      wantbytes ((long) (hstat.st_size), compare_dir);
  8593. X      free (data);
  8594. X    }
  8595. X      else
  8596. X    wantbytes ((long) (hstat.st_size), no_op);
  8597. X      /* FALL THROUGH */
  8598. X
  8599. X    case LF_DIR:
  8600. X      /* Check for trailing / */
  8601. X      namelen = strlen (current_file_name) - 1;
  8602. X    really_dir:
  8603. X      while (namelen && current_file_name[namelen] == '/')
  8604. X    current_file_name[namelen--] = '\0';    /* Zap / */
  8605. X
  8606. X      if (do_stat (&filestat))
  8607. X    break;
  8608. X      if (!S_ISDIR (filestat.st_mode))
  8609. X    {
  8610. X      fprintf (msg_file, "%s is no longer a directory\n", current_file_name);
  8611. X      different++;
  8612. X      break;
  8613. X    }
  8614. X      if ((filestat.st_mode & 07777) != (hstat.st_mode & 07777))
  8615. X    sigh ("mode");
  8616. X      break;
  8617. X
  8618. X    case LF_VOLHDR:
  8619. X      break;
  8620. X
  8621. X    case LF_MULTIVOL:
  8622. X      namelen = strlen (current_file_name) - 1;
  8623. X      if (current_file_name[namelen] == '/')
  8624. X    goto really_dir;
  8625. X
  8626. X      if (do_stat (&filestat))
  8627. X    break;
  8628. X
  8629. X      if (!S_ISREG (filestat.st_mode))
  8630. X    {
  8631. X      fprintf (msg_file, "%s: not a regular file\n",
  8632. X           current_file_name);
  8633. X      skip_file ((long) hstat.st_size);
  8634. X      different++;
  8635. X      break;
  8636. X    }
  8637. X
  8638. X      filestat.st_mode &= 07777;
  8639. X      offset = from_oct (1 + 12, head->header.offset);
  8640. X      if (filestat.st_size != hstat.st_size + offset)
  8641. X    {
  8642. X      sigh ("size");
  8643. X      skip_file ((long) hstat.st_size);
  8644. X      different++;
  8645. X      break;
  8646. X    }
  8647. X
  8648. X      diff_fd = open (current_file_name, O_NDELAY | O_RDONLY | O_BINARY);
  8649. X
  8650. X      if (diff_fd < 0)
  8651. X    {
  8652. X      msg_perror ("cannot open file %s", current_file_name);
  8653. X      skip_file ((long) hstat.st_size);
  8654. X      different++;
  8655. X      break;
  8656. X    }
  8657. X      err = lseek (diff_fd, offset, 0);
  8658. X      if (err != offset)
  8659. X    {
  8660. X      msg_perror ("cannot seek to %ld in file %s", offset, current_file_name);
  8661. X      different++;
  8662. X      break;
  8663. X    }
  8664. X
  8665. X      wantbytes ((long) (hstat.st_size), compare_chunk);
  8666. X
  8667. X      check = close (diff_fd);
  8668. X      if (check < 0)
  8669. X    {
  8670. X      msg_perror ("Error while closing %s", current_file_name);
  8671. X    }
  8672. X      break;
  8673. X
  8674. X    }
  8675. X
  8676. X  /* We don't need to save it any longer. */
  8677. X  saverec ((union record **) 0);/* Unsave it */
  8678. X}
  8679. X
  8680. Xint
  8681. Xcompare_chunk (bytes, buffer)
  8682. X     long bytes;
  8683. X     char *buffer;
  8684. X{
  8685. X  int err;
  8686. X
  8687. X  err = read (diff_fd, diff_buf, bytes);
  8688. X  if (err != bytes)
  8689. X    {
  8690. X      if (err < 0)
  8691. X    {
  8692. X      msg_perror ("can't read %s", current_file_name);
  8693. X    }
  8694. X      else
  8695. X    {
  8696. X      fprintf (msg_file, "%s: could only read %d of %d bytes\n", current_file_name, err, bytes);
  8697. X    }
  8698. X      different++;
  8699. X      return -1;
  8700. X    }
  8701. X  if (bcmp (buffer, diff_buf, bytes))
  8702. X    {
  8703. X      fprintf (msg_file, "%s: data differs\n", current_file_name);
  8704. X      different++;
  8705. X      return -1;
  8706. X    }
  8707. X  return 0;
  8708. X}
  8709. X
  8710. Xint
  8711. Xcompare_dir (bytes, buffer)
  8712. X     long bytes;
  8713. X     char *buffer;
  8714. X{
  8715. X  if (bcmp (buffer, diff_dir, bytes))
  8716. X    {
  8717. X      fprintf (msg_file, "%s: data differs\n", current_file_name);
  8718. X      different++;
  8719. X      return -1;
  8720. X    }
  8721. X  diff_dir += bytes;
  8722. X  return 0;
  8723. X}
  8724. X
  8725. X/*
  8726. X * Sigh about something that differs.
  8727. X */
  8728. Xvoid
  8729. Xsigh (what)
  8730. X     char *what;
  8731. X{
  8732. X
  8733. X  fprintf (msg_file, "%s: %s differs\n",
  8734. X       current_file_name, what);
  8735. X}
  8736. X
  8737. Xvoid
  8738. Xverify_volume ()
  8739. X{
  8740. X  int status;
  8741. X#ifdef MTIOCTOP
  8742. X  struct mtop t;
  8743. X  int er;
  8744. X#endif
  8745. X
  8746. X  if (!diff_buf)
  8747. X    diff_init ();
  8748. X#ifdef MTIOCTOP
  8749. X  t.mt_op = MTBSF;
  8750. X  t.mt_count = 1;
  8751. X  if ((er = rmtioctl (archive, MTIOCTOP, &t)) < 0)
  8752. X    {
  8753. X      if (errno != EIO || (er = rmtioctl (archive, MTIOCTOP, &t)) < 0)
  8754. X    {
  8755. X#endif
  8756. X      if (rmtlseek (archive, 0L, 0) != 0)
  8757. X        {
  8758. X          /* Lseek failed.  Try a different method */
  8759. X          msg_perror ("Couldn't rewind archive file for verify");
  8760. X          return;
  8761. X        }
  8762. X#ifdef MTIOCTOP
  8763. X    }
  8764. X    }
  8765. X#endif
  8766. X  ar_reading = 1;
  8767. X  now_verifying = 1;
  8768. X  fl_read ();
  8769. X  for (;;)
  8770. X    {
  8771. X      status = read_header ();
  8772. X      if (status == 0)
  8773. X    {
  8774. X      unsigned n;
  8775. X
  8776. X      n = 0;
  8777. X      do
  8778. X        {
  8779. X          n++;
  8780. X          status = read_header ();
  8781. X        }
  8782. X      while (status == 0);
  8783. X      msg ("VERIFY FAILURE: %d invalid header%s detected!", n, n == 1 ? "" : "s");
  8784. X    }
  8785. X      if (status == 2 || status == EOF)
  8786. X    break;
  8787. X      diff_archive ();
  8788. X    }
  8789. X  ar_reading = 0;
  8790. X  now_verifying = 0;
  8791. X
  8792. X}
  8793. X
  8794. Xint
  8795. Xdo_stat (statp)
  8796. X     struct stat *statp;
  8797. X{
  8798. X  int err;
  8799. X
  8800. X  err = f_follow_links ? stat (current_file_name, statp) : lstat (current_file_name, statp);
  8801. X  if (err < 0)
  8802. X    {
  8803. X      if (errno == ENOENT)
  8804. X    {
  8805. X      fprintf (msg_file, "%s: does not exist\n", current_file_name);
  8806. X    }
  8807. X      else
  8808. X    msg_perror ("can't stat file %s", current_file_name);
  8809. X      /*        skip_file((long)hstat.st_size);
  8810. X        different++;*/
  8811. X      return 1;
  8812. X    }
  8813. X  else
  8814. X    return 0;
  8815. X}
  8816. X
  8817. X/*
  8818. X * JK
  8819. X * Diff'ing a sparse file with its counterpart on the tar file is a
  8820. X * bit of a different story than a normal file.  First, we must know
  8821. X * what areas of the file to skip through, i.e., we need to contruct
  8822. X * a sparsearray, which will hold all the information we need.  We must
  8823. X * compare small amounts of data at a time as we find it.
  8824. X */
  8825. X
  8826. Xvoid
  8827. Xdiff_sparse_files (filesize)
  8828. X     int filesize;
  8829. X
  8830. X{
  8831. X  int sparse_ind = 0;
  8832. X  char *buf;
  8833. X  int buf_size = RECORDSIZE;
  8834. X  union record *datarec;
  8835. X  int err;
  8836. X  long numbytes;
  8837. X  /*    int        amt_read = 0;*/
  8838. X  int size = filesize;
  8839. X
  8840. X  buf = (char *) ck_malloc (buf_size * sizeof (char));
  8841. X
  8842. X  fill_in_sparse_array ();
  8843. X
  8844. X
  8845. X  while (size > 0)
  8846. X    {
  8847. X      datarec = findrec ();
  8848. X      if (!sparsearray[sparse_ind].numbytes)
  8849. X    break;
  8850. X
  8851. X      /*
  8852. X         * 'numbytes' is nicer to write than
  8853. X         * 'sparsearray[sparse_ind].numbytes' all the time ...
  8854. X         */
  8855. X      numbytes = sparsearray[sparse_ind].numbytes;
  8856. X
  8857. X      lseek (diff_fd, sparsearray[sparse_ind].offset, 0);
  8858. X      /*
  8859. X         * take care to not run out of room in our buffer
  8860. X         */
  8861. X      while (buf_size < numbytes)
  8862. X    {
  8863. X      buf = (char *) ck_realloc (buf, buf_size * 2 * sizeof (char));
  8864. X      buf_size *= 2;
  8865. X    }
  8866. X      while (numbytes > RECORDSIZE)
  8867. X    {
  8868. X      if ((err = read (diff_fd, buf, RECORDSIZE)) != RECORDSIZE)
  8869. X        {
  8870. X          if (err < 0)
  8871. X        msg_perror ("can't read %s", current_file_name);
  8872. X          else
  8873. X        fprintf (msg_file, "%s: could only read %d of %d bytes\n",
  8874. X             current_file_name, err, numbytes);
  8875. X          break;
  8876. X        }
  8877. X      if (bcmp (buf, datarec->charptr, RECORDSIZE))
  8878. X        {
  8879. X          different++;
  8880. X          break;
  8881. X        }
  8882. X      numbytes -= err;
  8883. X      size -= err;
  8884. X      userec (datarec);
  8885. X      datarec = findrec ();
  8886. X    }
  8887. X      if ((err = read (diff_fd, buf, numbytes)) != numbytes)
  8888. X    {
  8889. X      if (err < 0)
  8890. X        msg_perror ("can't read %s", current_file_name);
  8891. X      else
  8892. X        fprintf (msg_file, "%s: could only read %d of %d bytes\n",
  8893. X             current_file_name, err, numbytes);
  8894. X      break;
  8895. X    }
  8896. X
  8897. X      if (bcmp (buf, datarec->charptr, numbytes))
  8898. X    {
  8899. X      different++;
  8900. X      break;
  8901. X    }
  8902. X      /*        amt_read += numbytes;
  8903. X        if (amt_read >= RECORDSIZE) {
  8904. X            amt_read = 0;
  8905. X            userec(datarec);
  8906. X            datarec = findrec();
  8907. X        }*/
  8908. X      userec (datarec);
  8909. X      sparse_ind++;
  8910. X      size -= numbytes;
  8911. X    }
  8912. X  /*
  8913. X     * if the number of bytes read isn't the
  8914. X     * number of bytes supposedly in the file,
  8915. X     * they're different
  8916. X     */
  8917. X  /*    if (amt_read != filesize)
  8918. X        different++;*/
  8919. X  userec (datarec);
  8920. X  free (sparsearray);
  8921. X  if (different)
  8922. X    fprintf (msg_file, "%s: data differs\n", current_file_name);
  8923. X
  8924. X}
  8925. X
  8926. X/*
  8927. X * JK
  8928. X * This routine should be used more often than it is ... look into
  8929. X * that.  Anyhow, what it does is translate the sparse information
  8930. X * on the header, and in any subsequent extended headers, into an
  8931. X * array of structures with true numbers, as opposed to character
  8932. X * strings.  It simply makes our life much easier, doing so many
  8933. X * comparisong and such.
  8934. X */
  8935. Xvoid
  8936. Xfill_in_sparse_array ()
  8937. X{
  8938. X  int ind;
  8939. X
  8940. X  /*
  8941. X     * allocate space for our scratch space; it's initially
  8942. X     * 10 elements long, but can change in this routine if
  8943. X     * necessary
  8944. X     */
  8945. X  sp_array_size = 10;
  8946. X  sparsearray = (struct sp_array *) ck_malloc (sp_array_size * sizeof (struct sp_array));
  8947. X
  8948. X  /*
  8949. X     * there are at most five of these structures in the header
  8950. X     * itself; read these in first
  8951. X     */
  8952. X  for (ind = 0; ind < SPARSE_IN_HDR; ind++)
  8953. X    {
  8954. X      if (!head->header.sp[ind].numbytes)
  8955. X    break;
  8956. X      sparsearray[ind].offset =
  8957. X    from_oct (1 + 12, head->header.sp[ind].offset);
  8958. X      sparsearray[ind].numbytes =
  8959. X    from_oct (1 + 12, head->header.sp[ind].numbytes);
  8960. X    }
  8961. X  /*
  8962. X     * if the header's extended, we gotta read in exhdr's till
  8963. X     * we're done
  8964. X     */
  8965. X  if (head->header.isextended)
  8966. X    {
  8967. X      /* how far into the sparsearray we are 'so far' */
  8968. X      static int so_far_ind = SPARSE_IN_HDR;
  8969. X      union record *exhdr;
  8970. X
  8971. X      for (;;)
  8972. X    {
  8973. X      exhdr = findrec ();
  8974. X      for (ind = 0; ind < SPARSE_EXT_HDR; ind++)
  8975. X        {
  8976. X          if (ind + so_far_ind > sp_array_size - 1)
  8977. X        {
  8978. X          /*
  8979. X                  * we just ran out of room in our
  8980. X                 *  scratch area - realloc it
  8981. X                  */
  8982. X          sparsearray = (struct sp_array *)
  8983. X            ck_realloc (sparsearray,
  8984. X                 sp_array_size * 2 * sizeof (struct sp_array));
  8985. X          sp_array_size *= 2;
  8986. X        }
  8987. X          /*
  8988. X             * convert the character strings into longs
  8989. X             */
  8990. X          sparsearray[ind + so_far_ind].offset =
  8991. X        from_oct (1 + 12, exhdr->ext_hdr.sp[ind].offset);
  8992. X          sparsearray[ind + so_far_ind].numbytes =
  8993. X        from_oct (1 + 12, exhdr->ext_hdr.sp[ind].numbytes);
  8994. X        }
  8995. X      /*
  8996. X         * if this is the last extended header for this
  8997. X         * file, we can stop
  8998. X         */
  8999. X      if (!exhdr->ext_hdr.isextended)
  9000. X        break;
  9001. X      else
  9002. X        {
  9003. X          so_far_ind += SPARSE_EXT_HDR;
  9004. X          userec (exhdr);
  9005. X        }
  9006. X    }
  9007. X      /* be sure to skip past the last one  */
  9008. X      userec (exhdr);
  9009. X    }
  9010. X}
  9011. END_OF_FILE
  9012. if test 16692 -ne `wc -c <'diffarch.c'`; then
  9013.     echo shar: \"'diffarch.c'\" unpacked with wrong size!
  9014. fi
  9015. # end of 'diffarch.c'
  9016. fi
  9017. if test -f 'port.c' -a "${1}" != "-c" ; then 
  9018.   echo shar: Will not clobber existing file \"'port.c'\"
  9019. else
  9020. echo shar: Extracting \"'port.c'\" \(25899 characters\)
  9021. sed "s/^X//" >'port.c' <<'END_OF_FILE'
  9022. X/* Supporting routines which may sometimes be missing.
  9023. X   Copyright (C) 1988, 1992 Free Software Foundation
  9024. X
  9025. XThis file is part of GNU Tar.
  9026. X
  9027. XGNU Tar is free software; you can redistribute it and/or modify
  9028. Xit under the terms of the GNU General Public License as published by
  9029. Xthe Free Software Foundation; either version 2, or (at your option)
  9030. Xany later version.
  9031. X
  9032. XGNU Tar is distributed in the hope that it will be useful,
  9033. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  9034. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9035. XGNU General Public License for more details.
  9036. X
  9037. XYou should have received a copy of the GNU General Public License
  9038. Xalong with GNU Tar; see the file COPYING.  If not, write to
  9039. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  9040. X
  9041. X#include <stdio.h>
  9042. X#include <sys/types.h>
  9043. X#include <signal.h>
  9044. X#include <errno.h>
  9045. X#ifndef STDC_HEADERS
  9046. Xextern int errno;
  9047. X#endif
  9048. X
  9049. X#ifdef BSD42
  9050. X#include <sys/file.h>
  9051. X#else
  9052. X#ifndef V7
  9053. X#include <fcntl.h>
  9054. X#endif
  9055. X#endif
  9056. X
  9057. X#include "tar.h"
  9058. X#include "port.h"
  9059. X
  9060. Xextern long baserec;
  9061. X
  9062. X/* All machine-dependent #ifdefs should appear here, instead of
  9063. X   being scattered through the file.  For UN*X systems, it is better to
  9064. X   figure out what is needed in the configure script, for most of the
  9065. X   features. */
  9066. X
  9067. X#ifdef __MSDOS__
  9068. Xchar TTY_NAME[] = "con";
  9069. X#define HAVE_STRSTR
  9070. X#define HAVE_RENAME
  9071. X#define HAVE_MKDIR
  9072. X#else
  9073. Xchar TTY_NAME[] = "/dev/tty";
  9074. X#endif
  9075. X
  9076. X/* End of system-dependent #ifdefs */
  9077. X
  9078. X
  9079. X#ifndef HAVE_VALLOC
  9080. X/*
  9081. X * valloc() does a malloc() on a page boundary.  On some systems,
  9082. X * this can make large block I/O more efficient.
  9083. X */
  9084. Xchar *
  9085. Xvalloc (size)
  9086. X     unsigned size;
  9087. X{
  9088. X  return (malloc (size));
  9089. X}
  9090. X
  9091. X#endif /* !HAVE_VALLOC */
  9092. X
  9093. X#ifndef HAVE_MKDIR
  9094. X/*
  9095. X * Written by Robert Rother, Mariah Corporation, August 1985.
  9096. X *
  9097. X * If you want it, it's yours.  All I ask in return is that if you
  9098. X * figure out how to do this in a Bourne Shell script you send me
  9099. X * a copy.
  9100. X *                    sdcsvax!rmr or rmr@uscd
  9101. X *
  9102. X * Severely hacked over by John Gilmore to make a 4.2BSD compatible
  9103. X * subroutine.    11Mar86; hoptoad!gnu
  9104. X *
  9105. X * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
  9106. X * subroutine didn't return EEXIST.  It does now.
  9107. X */
  9108. X
  9109. X/*
  9110. X * Make a directory.
  9111. X */
  9112. Xint
  9113. Xmkdir (dpath, dmode)
  9114. X     char *dpath;
  9115. X     int dmode;
  9116. X{
  9117. X  int cpid, status;
  9118. X  struct stat statbuf;
  9119. X
  9120. X  if (stat (dpath, &statbuf) == 0)
  9121. X    {
  9122. X      errno = EEXIST;        /* Stat worked, so it already exists */
  9123. X      return -1;
  9124. X    }
  9125. X
  9126. X  /* If stat fails for a reason other than non-existence, return error */
  9127. X  if (errno != ENOENT)
  9128. X    return -1;
  9129. X
  9130. X  switch (cpid = fork ())
  9131. X    {
  9132. X
  9133. X    case -1:            /* Error in fork() */
  9134. X      return (-1);        /* Errno is set already */
  9135. X
  9136. X    case 0:            /* Child process */
  9137. X      /*
  9138. X         * Cheap hack to set mode of new directory.  Since this
  9139. X         * child process is going away anyway, we zap its umask.
  9140. X         * FIXME, this won't suffice to set SUID, SGID, etc. on this
  9141. X         * directory.  Does anybody care?
  9142. X         */
  9143. X      status = umask (0);    /* Get current umask */
  9144. X      status = umask (status | (0777 & ~dmode));    /* Set for mkdir */
  9145. X      execl ("/bin/mkdir", "mkdir", dpath, (char *) 0);
  9146. X      _exit (-1);        /* Can't exec /bin/mkdir */
  9147. X
  9148. X    default:            /* Parent process */
  9149. X      while (cpid != wait (&status));    /* Wait for kid to finish */
  9150. X    }
  9151. X
  9152. X  if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0)
  9153. X    {
  9154. X      errno = EIO;        /* We don't know why, but */
  9155. X      return -1;        /* /bin/mkdir failed */
  9156. X    }
  9157. X
  9158. X  return 0;
  9159. X}
  9160. X
  9161. Xint
  9162. Xrmdir (dpath)
  9163. X     char *dpath;
  9164. X{
  9165. X  int cpid, status;
  9166. X  struct stat statbuf;
  9167. X
  9168. X  if (stat (dpath, &statbuf) != 0)
  9169. X    {
  9170. X      /* Stat just set errno.  We don't have to */
  9171. X      return -1;
  9172. X    }
  9173. X
  9174. X  switch (cpid = fork ())
  9175. X    {
  9176. X
  9177. X    case -1:            /* Error in fork() */
  9178. X      return (-1);        /* Errno is set already */
  9179. X
  9180. X    case 0:            /* Child process */
  9181. X      execl ("/bin/rmdir", "rmdir", dpath, (char *) 0);
  9182. X      _exit (-1);        /* Can't exec /bin/mkdir */
  9183. X
  9184. X    default:            /* Parent process */
  9185. X      while (cpid != wait (&status));    /* Wait for kid to finish */
  9186. X    }
  9187. X
  9188. X  if (WIFSIGNALED (status) || WEXITSTATUS (status) != 0)
  9189. X    {
  9190. X      errno = EIO;        /* We don't know why, but */
  9191. X      return -1;        /* /bin/mkdir failed */
  9192. X    }
  9193. X
  9194. X  return 0;
  9195. X}
  9196. X
  9197. X#endif /* !HAVE_MKDIR */
  9198. X
  9199. X#ifndef HAVE_RENAME
  9200. X/* Rename file FROM to file TO.
  9201. X   Return 0 if successful, -1 if not. */
  9202. X
  9203. Xint
  9204. Xrename (from, to)
  9205. X     char *from;
  9206. X     char *to;
  9207. X{
  9208. X  struct stat from_stats;
  9209. X
  9210. X  if (stat (from, &from_stats))
  9211. X    return -1;
  9212. X
  9213. X  if (unlink (to) && errno != ENOENT)
  9214. X    return -1;
  9215. X
  9216. X  if (link (from, to))
  9217. X    return -1;
  9218. X
  9219. X  if (unlink (from) && errno != ENOENT)
  9220. X    {
  9221. X      unlink (to);
  9222. X      return -1;
  9223. X    }
  9224. X
  9225. X  return 0;
  9226. X}
  9227. X
  9228. X#endif /* !HAVE_RENAME */
  9229. X
  9230. X#ifdef minix
  9231. X/* Minix has bcopy but not bzero, and no memset.  Thanks, Andy. */
  9232. Xvoid
  9233. Xbzero (s1, n)
  9234. X     register char *s1;
  9235. X     register int n;
  9236. X{
  9237. X  while (n--)
  9238. X    *s1++ = '\0';
  9239. X}
  9240. X
  9241. X/* It also has no bcmp() */
  9242. Xint
  9243. Xbcmp (s1, s2, n)
  9244. X     register char *s1, *s2;
  9245. X     register int n;
  9246. X{
  9247. X  for (; n--; ++s1, ++s2)
  9248. X    {
  9249. X      if (*s1 != *s2)
  9250. X    return *s1 - *s2;
  9251. X    }
  9252. X  return 0;
  9253. X}
  9254. X
  9255. X/*
  9256. X * Groan, Minix doesn't have execlp either!
  9257. X *
  9258. X * execlp(file,arg0,arg1...argn,(char *)NULL)
  9259. X * exec a program, automatically searching for the program through
  9260. X * all the directories on the PATH.
  9261. X *
  9262. X * This version is naive about variable argument lists, it assumes
  9263. X * a straightforward C calling sequence.  If your system has odd stacks
  9264. X * *and* doesn't have execlp, YOU get to fix it.
  9265. X */
  9266. Xint
  9267. Xexeclp (filename, arg0)
  9268. X     char *filename, *arg0;
  9269. X{
  9270. X  register char *p, *path;
  9271. X  register char *fnbuffer;
  9272. X  char **argstart = &arg0;
  9273. X  struct stat statbuf;
  9274. X  extern char **environ;
  9275. X
  9276. X  if ((p = getenv ("PATH")) == NULL)
  9277. X    {
  9278. X      /* couldn't find path variable -- try to exec given filename */
  9279. X      return execve (filename, argstart, environ);
  9280. X    }
  9281. X
  9282. X  /*
  9283. X     * make a place to build the filename.  We malloc larger than we
  9284. X     * need, but we know it will fit in this.
  9285. X     */
  9286. X  fnbuffer = malloc (strlen (p) + 1 + strlen (filename));
  9287. X  if (fnbuffer == NULL)
  9288. X    {
  9289. X      errno = ENOMEM;
  9290. X      return -1;
  9291. X    }
  9292. X
  9293. X  /*
  9294. X     * try each component of the path to see if the file's there
  9295. X     * and executable.
  9296. X     */
  9297. X  for (path = p; path; path = p)
  9298. X    {
  9299. X      /* construct full path name to try */
  9300. X      if ((p = index (path, ':')) == NULL)
  9301. X    {
  9302. X      strcpy (fnbuffer, path);
  9303. X    }
  9304. X      else
  9305. X    {
  9306. X      strncpy (fnbuffer, path, p - path);
  9307. X      fnbuffer[p - path] = '\0';
  9308. X      p++;            /* Skip : for next time */
  9309. X    }
  9310. X      if (strlen (fnbuffer) != 0)
  9311. X    strcat (fnbuffer, "/");
  9312. X      strcat (fnbuffer, filename);
  9313. X
  9314. X      /* check to see if file is there and is a normal file */
  9315. X      if (stat (fnbuffer, &statbuf) < 0)
  9316. X    {
  9317. X      if (errno == ENOENT)
  9318. X        continue;        /* file not there,keep on looking */
  9319. X      else
  9320. X        goto fail;        /* failed for some reason, return */
  9321. X    }
  9322. X      if (!S_ISREG (statbuf.st_mode))
  9323. X    continue;
  9324. X
  9325. X      if (execve (fnbuffer, argstart, environ) < 0
  9326. X      && errno != ENOENT
  9327. X      && errno != ENOEXEC)
  9328. X    {
  9329. X      /* failed, for some other reason besides "file
  9330. X             * not found" or "not a.out format"
  9331. X             */
  9332. X      goto fail;
  9333. X    }
  9334. X
  9335. X      /*
  9336. X         * If we got error ENOEXEC, the file is executable but is
  9337. X         * not an object file.  Try to execute it as a shell script,
  9338. X         * returning error if we can't execute /bin/sh.
  9339. X         *
  9340. X         * FIXME, this code is broken in several ways.  Shell
  9341. X         * scripts should not in general be executed by the user's
  9342. X         * SHELL variable program.  On more mature systems, the
  9343. X         * script can specify with #!/bin/whatever.  Also, this
  9344. X         * code clobbers argstart[-1] if the exec of the shell
  9345. X         * fails.
  9346. X         */
  9347. X      if (errno == ENOEXEC)
  9348. X    {
  9349. X      char *shell;
  9350. X
  9351. X      /* Try to execute command "sh arg0 arg1 ..." */
  9352. X      if ((shell = getenv ("SHELL")) == NULL)
  9353. X        shell = "/bin/sh";
  9354. X      argstart[-1] = shell;
  9355. X      argstart[0] = fnbuffer;
  9356. X      execve (shell, &argstart[-1], environ);
  9357. X      goto fail;        /* Exec didn't work */
  9358. X    }
  9359. X
  9360. X      /*
  9361. X         * If we succeeded, the execve() doesn't return, so we
  9362. X         * can only be here is if the file hasn't been found yet.
  9363. X         * Try the next place on the path.
  9364. X         */
  9365. X    }
  9366. X
  9367. X  /* all attempts failed to locate the file.  Give up. */
  9368. X  errno = ENOENT;
  9369. X
  9370. Xfail:
  9371. X  free (fnbuffer);
  9372. X  return -1;
  9373. X}
  9374. X
  9375. X#endif /* minix */
  9376. X
  9377. X
  9378. X#ifdef EMUL_OPEN3
  9379. X#include "open3.h"
  9380. X/*
  9381. X * open3 -- routine to emulate the 3-argument open system
  9382. X * call that is present in most modern Unix systems.
  9383. X * This version attempts to support all the flag bits except for O_NDELAY
  9384. X * and O_APPEND, which are silently ignored.  The emulation is not as efficient
  9385. X * as the real thing (at worst, 4 system calls instead of one), but there's
  9386. X * not much I can do about that.
  9387. X *
  9388. X * Written 6/10/87 by rmtodd@uokmax
  9389. X *
  9390. X * open3(path, flag, mode)
  9391. X * Attempts to open the file specified by
  9392. X * the given pathname.  The following flag bits (#defined in tar.h)
  9393. X * specify options to the routine:
  9394. X *    O_RDONLY    file open for read only
  9395. X *    O_WRONLY    file open for write only
  9396. X *    O_RDWR        file open for both read & write
  9397. X * (Needless to say, you should only specify one of the above).
  9398. X *     O_CREAT        file is created with specified mode if it needs to be.
  9399. X *    O_TRUNC        if file exists, it is truncated to 0 bytes
  9400. X *    O_EXCL        used with O_CREAT--routine returns error if file exists
  9401. X * Function returns file descriptor if successful, -1 and errno if not.
  9402. X */
  9403. X
  9404. X/*
  9405. X * array to give arguments to access for various modes
  9406. X * FIXME, this table depends on the specific integer values of O_XXX,
  9407. X * and also contains integers (args to 'access') that should be #define's.
  9408. X */
  9409. Xstatic int modes[] =
  9410. X{
  9411. X  04,                /* O_RDONLY */
  9412. X  02,                /* O_WRONLY */
  9413. X  06,                /* O_RDWR */
  9414. X  06,                /* invalid but we'd better cope -- O_WRONLY+O_RDWR */
  9415. X};
  9416. X
  9417. X/* Shut off the automatic emulation of open(), we'll need it. */
  9418. X#undef open
  9419. X
  9420. Xint
  9421. Xopen3 (path, flags, mode)
  9422. X     char *path;
  9423. X     int flags, mode;
  9424. X{
  9425. X  int exists = 1;
  9426. X  int call_creat = 0;
  9427. X  int fd;
  9428. X  /*
  9429. X     * We actually do the work by calling the open() or creat() system
  9430. X     * call, depending on the flags.  Call_creat is true if we will use
  9431. X     * creat(), false if we will use open().
  9432. X     */
  9433. X
  9434. X  /*
  9435. X     * See if the file exists and is accessible in the requested mode.
  9436. X     *
  9437. X     * Strictly speaking we shouldn't be using access, since access checks
  9438. X     * against real uid, and the open call should check against euid.
  9439. X     * Most cases real uid == euid, so it won't matter.   FIXME.
  9440. X     * FIXME, the construction "flags & 3" and the modes table depends
  9441. X     * on the specific integer values of the O_XXX #define's.  Foo!
  9442. X     */
  9443. X  if (access (path, modes[flags & 3]) < 0)
  9444. X    {
  9445. X      if (errno == ENOENT)
  9446. X    {
  9447. X      /* the file does not exist */
  9448. X      exists = 0;
  9449. X    }
  9450. X      else
  9451. X    {
  9452. X      /* probably permission violation */
  9453. X      if (flags & O_EXCL)
  9454. X        {
  9455. X          /* Oops, the file exists, we didn't want it. */
  9456. X          /* No matter what the error, claim EEXIST. */
  9457. X          errno = EEXIST;
  9458. X        }
  9459. X      return -1;
  9460. X    }
  9461. X    }
  9462. X
  9463. X  /* if we have the O_CREAT bit set, check for O_EXCL */
  9464. X  if (flags & O_CREAT)
  9465. X    {
  9466. X      if ((flags & O_EXCL) && exists)
  9467. X    {
  9468. X      /* Oops, the file exists and we didn't want it to. */
  9469. X      errno = EEXIST;
  9470. X      return -1;
  9471. X    }
  9472. X      /*
  9473. X         * If the file doesn't exist, be sure to call creat() so that
  9474. X         * it will be created with the proper mode.
  9475. X         */
  9476. X      if (!exists)
  9477. X    call_creat = 1;
  9478. X    }
  9479. X  else
  9480. X    {
  9481. X      /* If O_CREAT isn't set and the file doesn't exist, error. */
  9482. X      if (!exists)
  9483. X    {
  9484. X      errno = ENOENT;
  9485. X      return -1;
  9486. X    }
  9487. X    }
  9488. X
  9489. X  /*
  9490. X     * If the O_TRUNC flag is set and the file exists, we want to call
  9491. X     * creat() anyway, since creat() guarantees that the file will be
  9492. X     * truncated and open()-for-writing doesn't.
  9493. X     * (If the file doesn't exist, we're calling creat() anyway and the
  9494. X     * file will be created with zero length.)
  9495. X     */
  9496. X  if ((flags & O_TRUNC) && exists)
  9497. X    call_creat = 1;
  9498. X  /* actually do the call */
  9499. X  if (call_creat)
  9500. X    {
  9501. X      /*
  9502. X         * call creat.  May have to close and reopen the file if we
  9503. X         * want O_RDONLY or O_RDWR access -- creat() only gives
  9504. X         * O_WRONLY.
  9505. X         */
  9506. X      fd = creat (path, mode);
  9507. X      if (fd < 0 || (flags & O_WRONLY))
  9508. X    return fd;
  9509. X      if (close (fd) < 0)
  9510. X    return -1;
  9511. X      /* Fall out to reopen the file we've created */
  9512. X    }
  9513. X
  9514. X  /*
  9515. X     * calling old open, we strip most of the new flags just in case.
  9516. X     */
  9517. X  return open (path, flags & (O_RDONLY | O_WRONLY | O_RDWR | O_BINARY));
  9518. X}
  9519. X
  9520. X#endif /* EMUL_OPEN3 */
  9521. X
  9522. X#ifndef HAVE_MKNOD
  9523. X#ifdef __MSDOS__
  9524. Xtypedef int dev_t;
  9525. X#endif
  9526. X/* Fake mknod by complaining */
  9527. Xint
  9528. Xmknod (path, mode, dev)
  9529. X     char *path;
  9530. X     unsigned short mode;
  9531. X     dev_t dev;
  9532. X{
  9533. X  int fd;
  9534. X
  9535. X  errno = ENXIO;        /* No such device or address */
  9536. X  return -1;            /* Just give an error */
  9537. X}
  9538. X
  9539. X/* Fake links by copying */
  9540. Xint
  9541. Xlink (path1, path2)
  9542. X     char *path1;
  9543. X     char *path2;
  9544. X{
  9545. X  char buf[256];
  9546. X  int ifd, ofd;
  9547. X  int nrbytes;
  9548. X  int nwbytes;
  9549. X
  9550. X  fprintf (stderr, "%s: %s: cannot link to %s, copying instead\n",
  9551. X       tar, path1, path2);
  9552. X  if ((ifd = open (path1, O_RDONLY | O_BINARY)) < 0)
  9553. X    return -1;
  9554. X  if ((ofd = creat (path2, 0666)) < 0)
  9555. X    return -1;
  9556. X  setmode (ofd, O_BINARY);
  9557. X  while ((nrbytes = read (ifd, buf, sizeof (buf))) > 0)
  9558. X    {
  9559. X      if ((nwbytes = write (ofd, buf, nrbytes)) != nrbytes)
  9560. X    {
  9561. X      nrbytes = -1;
  9562. X      break;
  9563. X    }
  9564. X    }
  9565. X  /* Note use of "|" rather than "||" below: we want to close
  9566. X     * the files even if an error occurs.
  9567. X     */
  9568. X  if ((nrbytes < 0) | (0 != close (ifd)) | (0 != close (ofd)))
  9569. X    {
  9570. X      unlink (path2);
  9571. X      return -1;
  9572. X    }
  9573. X  return 0;
  9574. X}
  9575. X
  9576. X/* everyone owns everything on MS-DOS (or is it no one owns anything?) */
  9577. Xint
  9578. Xchown (path, uid, gid)
  9579. X     char *path;
  9580. X     int uid;
  9581. X     int gid;
  9582. X{
  9583. X  return 0;
  9584. X}
  9585. X
  9586. Xint
  9587. Xgeteuid ()
  9588. X{
  9589. X  return 0;
  9590. X}
  9591. X
  9592. X#endif /* !HAVE_MKNOD */
  9593. X
  9594. X#ifdef __TURBOC__
  9595. X#include <time.h>
  9596. X#include <fcntl.h>
  9597. X#include <io.h>
  9598. X
  9599. Xstruct utimbuf
  9600. X{
  9601. X  time_t actime;        /* Access time. */
  9602. X  time_t modtime;        /* Modification time. */
  9603. X};
  9604. X
  9605. Xint
  9606. Xutime (char *filename, struct utimbuf *utb)
  9607. X{
  9608. X  struct tm *tm;
  9609. X  struct ftime filetime;
  9610. X  time_t when;
  9611. X  int fd;
  9612. X  int status;
  9613. X
  9614. X  if (utb == 0)
  9615. X    when = time (0);
  9616. X  else
  9617. X    when = utb->modtime;
  9618. X
  9619. X  fd = _open (filename, O_RDWR);
  9620. X  if (fd == -1)
  9621. X    return -1;
  9622. X
  9623. X  tm = localtime (&when);
  9624. X  if (tm->tm_year < 80)
  9625. X    filetime.ft_year = 0;
  9626. X  else
  9627. X    filetime.ft_year = tm->tm_year - 80;
  9628. X  filetime.ft_month = tm->tm_mon + 1;
  9629. X  filetime.ft_day = tm->tm_mday;
  9630. X  if (tm->tm_hour < 0)
  9631. X    filetime.ft_hour = 0;
  9632. X  else
  9633. X    filetime.ft_hour = tm->tm_hour;
  9634. X  filetime.ft_min = tm->tm_min;
  9635. X  filetime.ft_tsec = tm->tm_sec / 2;
  9636. X
  9637. X  status = setftime (fd, &filetime);
  9638. X  _close (fd);
  9639. X  return status;
  9640. X}
  9641. X
  9642. X#endif /* __TURBOC__ */
  9643. X
  9644. X/* Stash argv[0] here so panic will know what the program is called */
  9645. Xchar *myname = 0;
  9646. X
  9647. Xvoid
  9648. Xpanic (s)
  9649. X     char *s;
  9650. X{
  9651. X  if (myname)
  9652. X    fprintf (stderr, "%s:", myname);
  9653. X  fprintf (stderr, s);
  9654. X  putc ('\n', stderr);
  9655. X  exit (12);
  9656. X}
  9657. X
  9658. X
  9659. XPTR
  9660. Xck_malloc (size)
  9661. X     size_t size;
  9662. X{
  9663. X  PTR ret;
  9664. X
  9665. X  if (!size)
  9666. X    size++;
  9667. X  ret = malloc (size);
  9668. X  if (ret == 0)
  9669. X    panic ("Couldn't allocate memory");
  9670. X  return ret;
  9671. X}
  9672. X
  9673. X/* Used by alloca.c and bison.simple. */
  9674. Xchar *
  9675. Xxmalloc (size)
  9676. X     size_t size;
  9677. X{
  9678. X  return (char *) ck_malloc (size);
  9679. X}
  9680. X
  9681. XPTR
  9682. Xck_realloc (ptr, size)
  9683. X     PTR ptr;
  9684. X     size_t size;
  9685. X{
  9686. X  PTR ret;
  9687. X
  9688. X  if (!ptr)
  9689. X    ret = ck_malloc (size);
  9690. X  else
  9691. X    ret = realloc (ptr, size);
  9692. X  if (ret == 0)
  9693. X    panic ("Couldn't re-allocate memory");
  9694. X  return ret;
  9695. X}
  9696. X
  9697. X/* Implement a variable sized buffer of 'stuff'.  We don't know what it is,
  9698. X   nor do we care, as long as it doesn't mind being aligned on a char boundry.
  9699. X */
  9700. X
  9701. Xstruct buffer
  9702. X  {
  9703. X    int allocated;
  9704. X    int length;
  9705. X    char *b;
  9706. X  };
  9707. X
  9708. X#define MIN_ALLOCATE 50
  9709. X
  9710. Xchar *
  9711. Xinit_buffer ()
  9712. X{
  9713. X  struct buffer *b;
  9714. X
  9715. X  b = (struct buffer *) ck_malloc (sizeof (struct buffer));
  9716. X  b->allocated = MIN_ALLOCATE;
  9717. X  b->b = (char *) ck_malloc (MIN_ALLOCATE);
  9718. X  b->length = 0;
  9719. X  return (char *) b;
  9720. X}
  9721. X
  9722. Xvoid
  9723. Xflush_buffer (bb)
  9724. X     char *bb;
  9725. X{
  9726. X  struct buffer *b;
  9727. X
  9728. X  b = (struct buffer *) bb;
  9729. X  free (b->b);
  9730. X  b->b = 0;
  9731. X  b->allocated = 0;
  9732. X  b->length = 0;
  9733. X  free ((void *) b);
  9734. X}
  9735. X
  9736. Xvoid
  9737. Xadd_buffer (bb, p, n)
  9738. X     char *bb;
  9739. X     char *p;
  9740. X     int n;
  9741. X{
  9742. X  struct buffer *b;
  9743. X
  9744. X  b = (struct buffer *) bb;
  9745. X  if (b->length + n > b->allocated)
  9746. X    {
  9747. X      b->allocated = b->length + n + MIN_ALLOCATE;
  9748. X      b->b = (char *) ck_realloc (b->b, b->allocated);
  9749. X    }
  9750. X  bcopy (p, b->b + b->length, n);
  9751. X  b->length += n;
  9752. X}
  9753. X
  9754. Xchar *
  9755. Xget_buffer (bb)
  9756. X     char *bb;
  9757. X{
  9758. X  struct buffer *b;
  9759. X
  9760. X  b = (struct buffer *) bb;
  9761. X  return b->b;
  9762. X}
  9763. X
  9764. Xchar *
  9765. Xmerge_sort (list, n, off, cmp)
  9766. X     char *list;
  9767. X     int (*cmp) ();
  9768. X     unsigned n;
  9769. X     int off;
  9770. X{
  9771. X  char *ret;
  9772. X
  9773. X  char *alist, *blist;
  9774. X  unsigned alength, blength;
  9775. X
  9776. X  char *tptr;
  9777. X  int tmp;
  9778. X  char **prev;
  9779. X#define NEXTOF(ptr)    (* ((char **)(((char *)(ptr))+off) ) )
  9780. X  if (n == 1)
  9781. X    return list;
  9782. X  if (n == 2)
  9783. X    {
  9784. X      if ((*cmp) (list, NEXTOF (list)) > 0)
  9785. X    {
  9786. X      ret = NEXTOF (list);
  9787. X      NEXTOF (ret) = list;
  9788. X      NEXTOF (list) = 0;
  9789. X      return ret;
  9790. X    }
  9791. X      return list;
  9792. X    }
  9793. X  alist = list;
  9794. X  alength = (n + 1) / 2;
  9795. X  blength = n / 2;
  9796. X  for (tptr = list, tmp = (n - 1) / 2; tmp; tptr = NEXTOF (tptr), tmp--)
  9797. X    ;
  9798. X  blist = NEXTOF (tptr);
  9799. X  NEXTOF (tptr) = 0;
  9800. X
  9801. X  alist = merge_sort (alist, alength, off, cmp);
  9802. X  blist = merge_sort (blist, blength, off, cmp);
  9803. X  prev = &ret;
  9804. X  for (; alist && blist;)
  9805. X    {
  9806. X      if ((*cmp) (alist, blist) < 0)
  9807. X    {
  9808. X      tptr = NEXTOF (alist);
  9809. X      *prev = alist;
  9810. X      prev = &(NEXTOF (alist));
  9811. X      alist = tptr;
  9812. X    }
  9813. X      else
  9814. X    {
  9815. X      tptr = NEXTOF (blist);
  9816. X      *prev = blist;
  9817. X      prev = &(NEXTOF (blist));
  9818. X      blist = tptr;
  9819. X    }
  9820. X    }
  9821. X  if (alist)
  9822. X    *prev = alist;
  9823. X  else
  9824. X    *prev = blist;
  9825. X
  9826. X  return ret;
  9827. X}
  9828. X
  9829. Xvoid
  9830. Xck_close (fd)
  9831. X     int fd;
  9832. X{
  9833. X  if (close (fd) < 0)
  9834. X    {
  9835. X      msg_perror ("can't close a file #%d", fd);
  9836. X      exit (EX_SYSTEM);
  9837. X    }
  9838. X}
  9839. X
  9840. X#include <ctype.h>
  9841. X
  9842. X/* Quote_copy_string is like quote_string, but instead of modifying the
  9843. X   string in place, it malloc-s a copy  of the string, and returns that.
  9844. X   If the string does not have to be quoted, it returns the NULL string.
  9845. X   The allocated copy can, of course, be freed with free() after the
  9846. X   caller is done with it.
  9847. X */
  9848. Xchar *
  9849. Xquote_copy_string (string)
  9850. X     char *string;
  9851. X{
  9852. X  char *from_here;
  9853. X  char *to_there = 0;
  9854. X  char *copy_buf = 0;
  9855. X  int c;
  9856. X  int copying = 0;
  9857. X
  9858. X  from_here = string;
  9859. X  while (*from_here)
  9860. X    {
  9861. X      c = *from_here++;
  9862. X      if (c == '\\')
  9863. X    {
  9864. X      if (!copying)
  9865. X        {
  9866. X          int n;
  9867. X
  9868. X          n = (from_here - string) - 1;
  9869. X          copying++;
  9870. X          copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4);
  9871. X          if (!copy_buf)
  9872. X        return 0;
  9873. X          bcopy (string, copy_buf, n);
  9874. X          to_there = copy_buf + n;
  9875. X        }
  9876. X      *to_there++ = '\\';
  9877. X      *to_there++ = '\\';
  9878. X    }
  9879. X      else if (isprint (c))
  9880. X    {
  9881. X      if (copying)
  9882. X        *to_there++ = c;
  9883. X    }
  9884. X      else
  9885. X    {
  9886. X      if (!copying)
  9887. X        {
  9888. X          int n;
  9889. X
  9890. X          n = (from_here - string) - 1;
  9891. X          copying++;
  9892. X          copy_buf = (char *) malloc (n + 5 + strlen (from_here) * 4);
  9893. X          if (!copy_buf)
  9894. X        return 0;
  9895. X          bcopy (string, copy_buf, n);
  9896. X          to_there = copy_buf + n;
  9897. X        }
  9898. X      *to_there++ = '\\';
  9899. X      if (c == '\n')
  9900. X        *to_there++ = 'n';
  9901. X      else if (c == '\t')
  9902. X        *to_there++ = 't';
  9903. X      else if (c == '\f')
  9904. X        *to_there++ = 'f';
  9905. X      else if (c == '\b')
  9906. X        *to_there++ = 'b';
  9907. X      else if (c == '\r')
  9908. X        *to_there++ = 'r';
  9909. X      else if (c == '\177')
  9910. X        *to_there++ = '?';
  9911. X      else
  9912. X        {
  9913. X          to_there[0] = (c >> 6) + '0';
  9914. X          to_there[1] = ((c >> 3) & 07) + '0';
  9915. X          to_there[2] = (c & 07) + '0';
  9916. X          to_there += 3;
  9917. X        }
  9918. X    }
  9919. X    }
  9920. X  if (copying)
  9921. X    {
  9922. X      *to_there = '\0';
  9923. X      return copy_buf;
  9924. X    }
  9925. X  return (char *) 0;
  9926. X}
  9927. X
  9928. X
  9929. X/* Un_quote_string takes a quoted c-string (like those produced by
  9930. X   quote_string or quote_copy_string and turns it back into the
  9931. X   un-quoted original.  This is done in place.
  9932. X */
  9933. X
  9934. X/* There is no un-quote-copy-string.  Write it yourself */
  9935. X
  9936. Xchar *
  9937. Xun_quote_string (string)
  9938. X     char *string;
  9939. X{
  9940. X  char *ret;
  9941. X  char *from_here;
  9942. X  char *to_there;
  9943. X  int tmp;
  9944. X
  9945. X  ret = string;
  9946. X  to_there = string;
  9947. X  from_here = string;
  9948. X  while (*from_here)
  9949. X    {
  9950. X      if (*from_here != '\\')
  9951. X    {
  9952. X      if (from_here != to_there)
  9953. X        *to_there++ = *from_here++;
  9954. X      else
  9955. X        from_here++, to_there++;
  9956. X      continue;
  9957. X    }
  9958. X      switch (*++from_here)
  9959. X    {
  9960. X    case '\\':
  9961. X      *to_there++ = *from_here++;
  9962. X      break;
  9963. X    case 'n':
  9964. X      *to_there++ = '\n';
  9965. X      from_here++;
  9966. X      break;
  9967. X    case 't':
  9968. X      *to_there++ = '\t';
  9969. X      from_here++;
  9970. X      break;
  9971. X    case 'f':
  9972. X      *to_there++ = '\f';
  9973. X      from_here++;
  9974. X      break;
  9975. X    case 'b':
  9976. X      *to_there++ = '\b';
  9977. X      from_here++;
  9978. X      break;
  9979. X    case 'r':
  9980. X      *to_there++ = '\r';
  9981. X      from_here++;
  9982. X      break;
  9983. X    case '?':
  9984. X      *to_there++ = 0177;
  9985. X      from_here++;
  9986. X      break;
  9987. X    case '0':
  9988. X    case '1':
  9989. X    case '2':
  9990. X    case '3':
  9991. X    case '4':
  9992. X    case '5':
  9993. X    case '6':
  9994. X    case '7':
  9995. X      tmp = *from_here - '0';
  9996. X      from_here++;
  9997. X      if (*from_here < '0' || *from_here > '7')
  9998. X        {
  9999. X          *to_there++ = tmp;
  10000. X          break;
  10001. X        }
  10002. X      tmp = tmp * 8 + *from_here - '0';
  10003. X      from_here++;
  10004. X      if (*from_here < '0' || *from_here > '7')
  10005. X        {
  10006. X          *to_there++ = tmp;
  10007. X          break;
  10008. X        }
  10009. X      tmp = tmp * 8 + *from_here - '0';
  10010. X      from_here++;
  10011. X      *to_there = tmp;
  10012. X      break;
  10013. X    default:
  10014. X      ret = 0;
  10015. X      *to_there++ = '\\';
  10016. X      *to_there++ = *from_here++;
  10017. X      break;
  10018. X    }
  10019. X    }
  10020. X  if (*to_there)
  10021. X    *to_there++ = '\0';
  10022. X  return ret;
  10023. X}
  10024. X
  10025. X#ifndef __MSDOS__
  10026. Xvoid 
  10027. Xck_pipe (pipes)
  10028. X     int *pipes;
  10029. X{
  10030. X  if (pipe (pipes) < 0)
  10031. X    {
  10032. X      msg_perror ("can't open a pipe");
  10033. X      exit (EX_SYSTEM);
  10034. X    }
  10035. X}
  10036. X#endif /* !__MSDOS__ */
  10037. X
  10038. X#ifndef HAVE_STRSTR
  10039. X/*
  10040. X * strstr - find first occurrence of wanted in s
  10041. X */
  10042. X
  10043. Xchar *                /* found string, or NULL if none */
  10044. Xstrstr (s, wanted)
  10045. X     char *s;
  10046. X     char *wanted;
  10047. X{
  10048. X  register char *scan;
  10049. X  register size_t len;
  10050. X  register char firstc;
  10051. X
  10052. X  if (*wanted == '\0')
  10053. X    return (char *) 0;
  10054. X  /*
  10055. X     * The odd placement of the two tests is so "" is findable.
  10056. X     * Also, we inline the first char for speed.
  10057. X     * The ++ on scan has been moved down for optimization.
  10058. X     */
  10059. X  firstc = *wanted;
  10060. X  len = strlen (wanted);
  10061. X  for (scan = s; *scan != firstc || strncmp (scan, wanted, len) != 0;)
  10062. X    if (*scan++ == '\0')
  10063. X      return (char *) 0;
  10064. X  return scan;
  10065. X}
  10066. X
  10067. X#endif /* !HAVE_STRSTR */
  10068. X
  10069. X#ifndef HAVE_FTRUNCATE
  10070. X
  10071. X#ifdef F_CHSIZE
  10072. Xint
  10073. Xftruncate (fd, length)
  10074. X     int fd;
  10075. X     off_t length;
  10076. X{
  10077. X  return fcntl (fd, F_CHSIZE, length);
  10078. X}
  10079. X
  10080. X#else /* !F_CHSIZE */
  10081. X#ifdef F_FREESP
  10082. X/* code courtesy of William Kucharski, kucharsk@Solbourne.com */
  10083. X
  10084. Xint
  10085. Xftruncate (fd, length)
  10086. X     int fd;            /* file descriptor */
  10087. X     off_t length;        /* length to set file to */
  10088. X{
  10089. X  struct flock fl;
  10090. X
  10091. X  fl.l_whence = 0;
  10092. X  fl.l_len = 0;
  10093. X  fl.l_start = length;
  10094. X  fl.l_type = F_WRLCK;        /* write lock on file space */
  10095. X
  10096. X  /*
  10097. X     * This relies on the UNDOCUMENTED F_FREESP argument to
  10098. X     * fcntl(2), which truncates the file so that it ends at the
  10099. X     * position indicated by fl.l_start.
  10100. X     *
  10101. X     * Will minor miracles never cease?
  10102. X     */
  10103. X
  10104. X  if (fcntl (fd, F_FREESP, &fl) < 0)
  10105. X    return -1;
  10106. X
  10107. X  return 0;
  10108. X}
  10109. X
  10110. X#else /* !F_FREESP */
  10111. X
  10112. Xint
  10113. Xftruncate (fd, length)
  10114. X     int fd;
  10115. X     off_t length;
  10116. X{
  10117. X  errno = EIO;
  10118. X  return -1;
  10119. X}
  10120. X
  10121. X#endif /* !F_FREESP */
  10122. X#endif /* !F_CHSIZE */
  10123. X#endif /* !HAVE_FTRUNCATE */
  10124. X
  10125. X
  10126. Xextern FILE *msg_file;
  10127. X
  10128. X#if defined (HAVE_VPRINTF) && __STDC__
  10129. X#include <stdarg.h>
  10130. X
  10131. Xvoid
  10132. Xmsg (char *str,...)
  10133. X{
  10134. X  va_list args;
  10135. X
  10136. X  va_start (args, str);
  10137. X  fflush (msg_file);
  10138. X  fprintf (stderr, "%s: ", tar);
  10139. X  if (f_sayblock)
  10140. X    fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
  10141. X  vfprintf (stderr, str, args);
  10142. X  va_end (args);
  10143. X  putc ('\n', stderr);
  10144. X  fflush (stderr);
  10145. X}
  10146. X
  10147. Xvoid
  10148. Xmsg_perror (char *str,...)
  10149. X{
  10150. X  va_list args;
  10151. X  int save_e;
  10152. X
  10153. X  save_e = errno;
  10154. X  fflush (msg_file);
  10155. X  fprintf (stderr, "%s: ", tar);
  10156. X  if (f_sayblock)
  10157. X    fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
  10158. X  va_start (args, str);
  10159. X  vfprintf (stderr, str, args);
  10160. X  va_end (args);
  10161. X  errno = save_e;
  10162. X  perror (" ");
  10163. X  fflush (stderr);
  10164. X}
  10165. X
  10166. X#endif /* HAVE_VPRINTF and __STDC__ */
  10167. X
  10168. X#if defined(HAVE_VPRINTF) && !__STDC__
  10169. X#include <varargs.h>
  10170. Xvoid
  10171. Xmsg (str, va_alist)
  10172. X     char *str;
  10173. X     va_dcl
  10174. X{
  10175. X  va_list args;
  10176. X
  10177. X  fflush (msg_file);
  10178. X  fprintf (stderr, "%s: ", tar);
  10179. X  if (f_sayblock)
  10180. X    fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
  10181. X  va_start (args);
  10182. X  vfprintf (stderr, str, args);
  10183. X  va_end (args);
  10184. X  putc ('\n', stderr);
  10185. X  fflush (stderr);
  10186. X}
  10187. X
  10188. Xvoid
  10189. Xmsg_perror (str, va_alist)
  10190. X     char *str;
  10191. X     va_dcl
  10192. X{
  10193. X  va_list args;
  10194. X  int save_e;
  10195. X
  10196. X  save_e = errno;
  10197. X  fflush (msg_file);
  10198. X  fprintf (stderr, "%s: ", tar);
  10199. X  if (f_sayblock)
  10200. X    fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
  10201. X  va_start (args);
  10202. X  vfprintf (stderr, str, args);
  10203. X  va_end (args);
  10204. X  errno = save_e;
  10205. X  perror (" ");
  10206. X  fflush (stderr);
  10207. X}
  10208. X
  10209. X#endif /* HAVE_VPRINTF and not __STDC__ */
  10210. X
  10211. X#if !defined(HAVE_VPRINTF) && defined(HAVE_DOPRNT)
  10212. Xvoid
  10213. Xmsg (str, args)
  10214. X     char *str;
  10215. X     int args;
  10216. X{
  10217. X  fflush (msg_file);
  10218. X  fprintf (stderr, "%s: ", tar);
  10219. X  if (f_sayblock)
  10220. X    fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
  10221. X  _doprnt (str, &args, stderr);
  10222. X  putc ('\n', stderr);
  10223. X  fflush (stderr);
  10224. X}
  10225. X
  10226. Xvoid
  10227. Xmsg_perror (str, args)
  10228. X     char *str;
  10229. X     int args;
  10230. X{
  10231. X  int save_e;
  10232. X
  10233. X  save_e = errno;
  10234. X  fflush (msg_file);
  10235. X  fprintf (stderr, "%s: ", tar);
  10236. X  if (f_sayblock)
  10237. X    fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
  10238. X  _doprnt (str, &args, stderr);
  10239. X  errno = save_e;
  10240. X  perror (" ");
  10241. X  fflush (stderr);
  10242. X}
  10243. X
  10244. X#endif /* !HAVE_VPRINTF and HAVE_DOPRNT */
  10245. X
  10246. X#if !defined(HAVE_VPRINTF) && !defined(HAVE_DOPRNT)
  10247. Xvoid 
  10248. Xmsg (str, a1, a2, a3, a4, a5, a6)
  10249. X     char *str;
  10250. X{
  10251. X  fflush (msg_file);
  10252. X  fprintf (stderr, "%s: ", tar);
  10253. X  if (f_sayblock)
  10254. X    fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
  10255. X  fprintf (stderr, str, a1, a2, a3, a4, a5, a6);
  10256. X  putc ('\n', stderr);
  10257. X  fflush (stderr);
  10258. X}
  10259. X
  10260. Xvoid
  10261. Xmsg_perror (str, a1, a2, a3, a4, a5, a6)
  10262. X     char *str;
  10263. X{
  10264. X  int save_e;
  10265. X
  10266. X  save_e = errno;
  10267. X  fflush (msg_file);
  10268. X  fprintf (stderr, "%s: ", tar);
  10269. X  if (f_sayblock)
  10270. X    fprintf (stderr, "rec %d: ", baserec + (ar_record - ar_block));
  10271. X  fprintf (stderr, str, a1, a2, a3, a4, a5, a6);
  10272. X  fprintf (stderr, ": ");
  10273. X  errno = save_e;
  10274. X  perror (" ");
  10275. X}
  10276. X
  10277. X#endif /* !HAVE_VPRINTF and !HAVE_DOPRNT */
  10278. END_OF_FILE
  10279. if test 25899 -ne `wc -c <'port.c'`; then
  10280.     echo shar: \"'port.c'\" unpacked with wrong size!
  10281. fi
  10282. # end of 'port.c'
  10283. fi
  10284. if test -f 'fnmatch.c' -a "${1}" != "-c" ; then 
  10285.   echo shar: Will not clobber existing file \"'fnmatch.c'\"
  10286. else
  10287. echo shar: Extracting \"'fnmatch.c'\" \(3960 characters\)
  10288. sed "s/^X//" >'fnmatch.c' <<'END_OF_FILE'
  10289. X/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  10290. X
  10291. XThis library is free software; you can redistribute it and/or
  10292. Xmodify it under the terms of the GNU Library General Public License as
  10293. Xpublished by the Free Software Foundation; either version 2 of the
  10294. XLicense, or (at your option) any later version.
  10295. X
  10296. XThis library is distributed in the hope that it will be useful,
  10297. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  10298. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  10299. XLibrary General Public License for more details.
  10300. X
  10301. XYou should have received a copy of the GNU Library General Public
  10302. XLicense along with this library; see the file COPYING.LIB.  If
  10303. Xnot, write to the Free Software Foundation, Inc., 675 Mass Ave,
  10304. XCambridge, MA 02139, USA.  */
  10305. X
  10306. X#include <errno.h>
  10307. X#include <fnmatch.h>
  10308. X
  10309. X#if !defined(__GNU_LIBRARY__) && !defined(STDC_HEADERS)
  10310. Xextern int errno;
  10311. X#endif
  10312. X
  10313. X/* Match STRING against the filename pattern PATTERN, returning zero if
  10314. X   it matches, nonzero if not.  */
  10315. Xint
  10316. Xfnmatch (pattern, string, flags)
  10317. X     const char *pattern;
  10318. X     const char *string;
  10319. X     int flags;
  10320. X{
  10321. X  register const char *p = pattern, *n = string;
  10322. X  register char c;
  10323. X
  10324. X  if ((flags & ~__FNM_FLAGS) != 0)
  10325. X    {
  10326. X      errno = EINVAL;
  10327. X      return -1;
  10328. X    }
  10329. X
  10330. X  while ((c = *p++) != '\0')
  10331. X    {
  10332. X      switch (c)
  10333. X    {
  10334. X    case '?':
  10335. X      if (*n == '\0')
  10336. X        return FNM_NOMATCH;
  10337. X      else if ((flags & FNM_PATHNAME) && *n == '/')
  10338. X        return FNM_NOMATCH;
  10339. X      else if ((flags & FNM_PERIOD) && *n == '.' &&
  10340. X           (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
  10341. X        return FNM_NOMATCH;
  10342. X      break;
  10343. X
  10344. X    case '\\':
  10345. X      if (!(flags & FNM_NOESCAPE))
  10346. X        c = *p++;
  10347. X      if (*n != c)
  10348. X        return FNM_NOMATCH;
  10349. X      break;
  10350. X
  10351. X    case '*':
  10352. X      if ((flags & FNM_PERIOD) && *n == '.' &&
  10353. X          (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
  10354. X        return FNM_NOMATCH;
  10355. X
  10356. X      for (c = *p++; c == '?' || c == '*'; c = *p++, ++n)
  10357. X        if (((flags & FNM_PATHNAME) && *n == '/') ||
  10358. X        (c == '?' && *n == '\0'))
  10359. X          return FNM_NOMATCH;
  10360. X
  10361. X      if (c == '\0')
  10362. X        return 0;
  10363. X
  10364. X      {
  10365. X        char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c;
  10366. X        for (--p; *n != '\0'; ++n)
  10367. X          if ((c == '[' || *n == c1) &&
  10368. X          fnmatch (p, n, flags & ~FNM_PERIOD) == 0)
  10369. X        return 0;
  10370. X        return FNM_NOMATCH;
  10371. X      }
  10372. X
  10373. X    case '[':
  10374. X      {
  10375. X        /* Nonzero if the sense of the character class is inverted.  */
  10376. X        register int not;
  10377. X
  10378. X        if (*n == '\0')
  10379. X          return FNM_NOMATCH;
  10380. X
  10381. X        if ((flags & FNM_PERIOD) && *n == '.' &&
  10382. X        (n == string || ((flags & FNM_PATHNAME) && n[-1] == '/')))
  10383. X          return FNM_NOMATCH;
  10384. X
  10385. X        not = (*p == '!' || *p == '^');
  10386. X        if (not)
  10387. X          ++p;
  10388. X
  10389. X        c = *p++;
  10390. X        for (;;)
  10391. X          {
  10392. X        register char cstart = c, cend = c;
  10393. X
  10394. X        if (!(flags & FNM_NOESCAPE) && c == '\\')
  10395. X          cstart = cend = *p++;
  10396. X
  10397. X        if (c == '\0')
  10398. X          /* [ (unterminated) loses.  */
  10399. X          return FNM_NOMATCH;
  10400. X
  10401. X        c = *p++;
  10402. X
  10403. X        if ((flags & FNM_PATHNAME) && c == '/')
  10404. X          /* [/] can never match.  */
  10405. X          return FNM_NOMATCH;
  10406. X
  10407. X        if (c == '-' && *p != ']')
  10408. X          {
  10409. X            cend = *p++;
  10410. X            if (!(flags & FNM_NOESCAPE) && cend == '\\')
  10411. X              cend = *p++;
  10412. X            if (cend == '\0')
  10413. X              return FNM_NOMATCH;
  10414. X            c = *p++;
  10415. X          }
  10416. X
  10417. X        if (*n >= cstart && *n <= cend)
  10418. X          goto matched;
  10419. X
  10420. X        if (c == ']')
  10421. X          break;
  10422. X          }
  10423. X        if (!not)
  10424. X          return FNM_NOMATCH;
  10425. X        break;
  10426. X
  10427. X      matched:;
  10428. X        /* Skip the rest of the [...] that already matched.  */
  10429. X        while (c != ']')
  10430. X          {
  10431. X        if (c == '\0')
  10432. X          /* [... (unterminated) loses.  */
  10433. X          return FNM_NOMATCH;
  10434. X
  10435. X        c = *p++;
  10436. X        if (!(flags & FNM_NOESCAPE) && c == '\\')
  10437. X          /* 1003.2d11 is unclear if this is right.  %%% */
  10438. X          ++p;
  10439. X          }
  10440. X        if (not)
  10441. X          return FNM_NOMATCH;
  10442. X      }
  10443. X      break;
  10444. X
  10445. X    default:
  10446. X      if (c != *n)
  10447. X        return FNM_NOMATCH;
  10448. X    }
  10449. X
  10450. X      ++n;
  10451. X    }
  10452. X
  10453. X  if (*n == '\0')
  10454. X    return 0;
  10455. X
  10456. X  if ((flags & FNM_LEADING_DIR) && *n == '/')
  10457. X    /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz".  */
  10458. X    return 0;
  10459. X
  10460. X  return FNM_NOMATCH;
  10461. X}
  10462. END_OF_FILE
  10463. if test 3960 -ne `wc -c <'fnmatch.c'`; then
  10464.     echo shar: \"'fnmatch.c'\" unpacked with wrong size!
  10465. fi
  10466. # end of 'fnmatch.c'
  10467. fi
  10468. if test -f 'getopt.c' -a "${1}" != "-c" ; then 
  10469.   echo shar: Will not clobber existing file \"'getopt.c'\"
  10470. else
  10471. echo shar: Extracting \"'getopt.c'\" \(20137 characters\)
  10472. sed "s/^X//" >'getopt.c' <<'END_OF_FILE'
  10473. X/* Getopt for GNU.
  10474. X   NOTE: getopt is now part of the C library, so if you don't know what
  10475. X   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
  10476. X   before changing it!
  10477. X
  10478. X   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
  10479. X       Free Software Foundation, Inc.
  10480. X
  10481. X   This program is free software; you can redistribute it and/or modify it
  10482. X   under the terms of the GNU General Public License as published by the
  10483. X   Free Software Foundation; either version 2, or (at your option) any
  10484. X   later version.
  10485. X   
  10486. X   This program is distributed in the hope that it will be useful,
  10487. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  10488. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10489. X   GNU General Public License for more details.
  10490. X   
  10491. X   You should have received a copy of the GNU General Public License
  10492. X   along with this program; if not, write to the Free Software
  10493. X   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  10494. X
  10495. X/* NOTE!!!  AIX requires this to be the first thing in the file.
  10496. X   Do not put ANYTHING before it!  */
  10497. X#if !defined (__GNUC__) && defined (_AIX)
  10498. X #pragma alloca
  10499. X#endif
  10500. X
  10501. X#ifdef HAVE_CONFIG_H
  10502. X#include "config.h"
  10503. X#endif
  10504. X
  10505. X#ifdef __GNUC__
  10506. X#define alloca __builtin_alloca
  10507. X#else /* not __GNUC__ */
  10508. X#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
  10509. X#include <alloca.h>
  10510. X#else
  10511. X#ifndef _AIX
  10512. Xchar *alloca ();
  10513. X#endif
  10514. X#endif /* alloca.h */
  10515. X#endif /* not __GNUC__ */
  10516. X
  10517. X#if !__STDC__ && !defined(const) && IN_GCC
  10518. X#define const
  10519. X#endif
  10520. X
  10521. X#include <stdio.h>
  10522. X
  10523. X/* This needs to come after some library #include
  10524. X   to get __GNU_LIBRARY__ defined.  */
  10525. X#ifdef    __GNU_LIBRARY__
  10526. X#undef    alloca
  10527. X/* Don't include stdlib.h for non-GNU C libraries because some of them
  10528. X   contain conflicting prototypes for getopt.  */
  10529. X#include <stdlib.h>
  10530. X#else    /* Not GNU C library.  */
  10531. X#define    __alloca    alloca
  10532. X#endif    /* GNU C library.  */
  10533. X
  10534. X/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
  10535. X   long-named option.  Because this is not POSIX.2 compliant, it is
  10536. X   being phased out.  */
  10537. X/* #define GETOPT_COMPAT */
  10538. X
  10539. X/* This version of `getopt' appears to the caller like standard Unix `getopt'
  10540. X   but it behaves differently for the user, since it allows the user
  10541. X   to intersperse the options with the other arguments.
  10542. X
  10543. X   As `getopt' works, it permutes the elements of ARGV so that,
  10544. X   when it is done, all the options precede everything else.  Thus
  10545. X   all application programs are extended to handle flexible argument order.
  10546. X
  10547. X   Setting the environment variable POSIXLY_CORRECT disables permutation.
  10548. X   Then the behavior is completely standard.
  10549. X
  10550. X   GNU application programs can use a third alternative mode in which
  10551. X   they can distinguish the relative order of options and other arguments.  */
  10552. X
  10553. X#include "getopt.h"
  10554. X
  10555. X/* For communication from `getopt' to the caller.
  10556. X   When `getopt' finds an option that takes an argument,
  10557. X   the argument value is returned here.
  10558. X   Also, when `ordering' is RETURN_IN_ORDER,
  10559. X   each non-option ARGV-element is returned here.  */
  10560. X
  10561. Xchar *optarg = 0;
  10562. X
  10563. X/* Index in ARGV of the next element to be scanned.
  10564. X   This is used for communication to and from the caller
  10565. X   and for communication between successive calls to `getopt'.
  10566. X
  10567. X   On entry to `getopt', zero means this is the first call; initialize.
  10568. X
  10569. X   When `getopt' returns EOF, this is the index of the first of the
  10570. X   non-option elements that the caller should itself scan.
  10571. X
  10572. X   Otherwise, `optind' communicates from one call to the next
  10573. X   how much of ARGV has been scanned so far.  */
  10574. X
  10575. X/* XXX 1003.2 says this must be 1 before any call.  */
  10576. Xint optind = 0;
  10577. X
  10578. X/* The next char to be scanned in the option-element
  10579. X   in which the last option character we returned was found.
  10580. X   This allows us to pick up the scan where we left off.
  10581. X
  10582. X   If this is zero, or a null string, it means resume the scan
  10583. X   by advancing to the next ARGV-element.  */
  10584. X
  10585. Xstatic char *nextchar;
  10586. X
  10587. X/* Callers store zero here to inhibit the error message
  10588. X   for unrecognized options.  */
  10589. X
  10590. Xint opterr = 1;
  10591. X
  10592. X/* Set to an option character which was unrecognized.
  10593. X   This must be initialized on some systems to avoid linking in the
  10594. X   system's own getopt implementation.  */
  10595. X
  10596. Xint optopt = '?';
  10597. X
  10598. X/* Describe how to deal with options that follow non-option ARGV-elements.
  10599. X
  10600. X   If the caller did not specify anything,
  10601. X   the default is REQUIRE_ORDER if the environment variable
  10602. X   POSIXLY_CORRECT is defined, PERMUTE otherwise.
  10603. X
  10604. X   REQUIRE_ORDER means don't recognize them as options;
  10605. X   stop option processing when the first non-option is seen.
  10606. X   This is what Unix does.
  10607. X   This mode of operation is selected by either setting the environment
  10608. X   variable POSIXLY_CORRECT, or using `+' as the first character
  10609. X   of the list of option characters.
  10610. X
  10611. X   PERMUTE is the default.  We permute the contents of ARGV as we scan,
  10612. X   so that eventually all the non-options are at the end.  This allows options
  10613. X   to be given in any order, even with programs that were not written to
  10614. X   expect this.
  10615. X
  10616. X   RETURN_IN_ORDER is an option available to programs that were written
  10617. X   to expect options and other ARGV-elements in any order and that care about
  10618. X   the ordering of the two.  We describe each non-option ARGV-element
  10619. X   as if it were the argument of an option with character code 1.
  10620. X   Using `-' as the first character of the list of option characters
  10621. X   selects this mode of operation.
  10622. X
  10623. X   The special argument `--' forces an end of option-scanning regardless
  10624. X   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
  10625. X   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
  10626. X
  10627. Xstatic enum
  10628. X{
  10629. X  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
  10630. X} ordering;
  10631. X
  10632. X#ifdef    __GNU_LIBRARY__
  10633. X/* We want to avoid inclusion of string.h with non-GNU libraries
  10634. X   because there are many ways it can cause trouble.
  10635. X   On some systems, it contains special magic macros that don't work
  10636. X   in GCC.  */
  10637. X#include <string.h>
  10638. X#define    my_index    strchr
  10639. X#define    my_bcopy(src, dst, n)    memcpy ((dst), (src), (n))
  10640. X#else
  10641. X
  10642. X/* Avoid depending on library functions or files
  10643. X   whose names are inconsistent.  */
  10644. X
  10645. Xchar *getenv ();
  10646. X
  10647. Xstatic char *
  10648. Xmy_index (string, chr)
  10649. X     char *string;
  10650. X     int chr;
  10651. X{
  10652. X  while (*string)
  10653. X    {
  10654. X      if (*string == chr)
  10655. X    return string;
  10656. X      string++;
  10657. X    }
  10658. X  return 0;
  10659. X}
  10660. X
  10661. Xstatic void
  10662. Xmy_bcopy (from, to, size)
  10663. X     char *from, *to;
  10664. X     int size;
  10665. X{
  10666. X  int i;
  10667. X  for (i = 0; i < size; i++)
  10668. X    to[i] = from[i];
  10669. X}
  10670. X#endif                /* GNU C library.  */
  10671. X
  10672. X/* Handle permutation of arguments.  */
  10673. X
  10674. X/* Describe the part of ARGV that contains non-options that have
  10675. X   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
  10676. X   `last_nonopt' is the index after the last of them.  */
  10677. X
  10678. Xstatic int first_nonopt;
  10679. Xstatic int last_nonopt;
  10680. X
  10681. X/* Exchange two adjacent subsequences of ARGV.
  10682. X   One subsequence is elements [first_nonopt,last_nonopt)
  10683. X   which contains all the non-options that have been skipped so far.
  10684. X   The other is elements [last_nonopt,optind), which contains all
  10685. X   the options processed since those non-options were skipped.
  10686. X
  10687. X   `first_nonopt' and `last_nonopt' are relocated so that they describe
  10688. X   the new indices of the non-options in ARGV after they are moved.  */
  10689. X
  10690. Xstatic void
  10691. Xexchange (argv)
  10692. X     char **argv;
  10693. X{
  10694. X  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
  10695. X  char **temp = (char **) __alloca (nonopts_size);
  10696. X
  10697. X  /* Interchange the two blocks of data in ARGV.  */
  10698. X
  10699. X  my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
  10700. X  my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
  10701. X        (optind - last_nonopt) * sizeof (char *));
  10702. X  my_bcopy ((char *) temp,
  10703. X        (char *) &argv[first_nonopt + optind - last_nonopt],
  10704. X        nonopts_size);
  10705. X
  10706. X  /* Update records for the slots the non-options now occupy.  */
  10707. X
  10708. X  first_nonopt += (optind - last_nonopt);
  10709. X  last_nonopt = optind;
  10710. X}
  10711. X
  10712. X/* Scan elements of ARGV (whose length is ARGC) for option characters
  10713. X   given in OPTSTRING.
  10714. X
  10715. X   If an element of ARGV starts with '-', and is not exactly "-" or "--",
  10716. X   then it is an option element.  The characters of this element
  10717. X   (aside from the initial '-') are option characters.  If `getopt'
  10718. X   is called repeatedly, it returns successively each of the option characters
  10719. X   from each of the option elements.
  10720. X
  10721. X   If `getopt' finds another option character, it returns that character,
  10722. X   updating `optind' and `nextchar' so that the next call to `getopt' can
  10723. X   resume the scan with the following option character or ARGV-element.
  10724. X
  10725. X   If there are no more option characters, `getopt' returns `EOF'.
  10726. X   Then `optind' is the index in ARGV of the first ARGV-element
  10727. X   that is not an option.  (The ARGV-elements have been permuted
  10728. X   so that those that are not options now come last.)
  10729. X
  10730. X   OPTSTRING is a string containing the legitimate option characters.
  10731. X   If an option character is seen that is not listed in OPTSTRING,
  10732. X   return '?' after printing an error message.  If you set `opterr' to
  10733. X   zero, the error message is suppressed but we still return '?'.
  10734. X
  10735. X   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
  10736. X   so the following text in the same ARGV-element, or the text of the following
  10737. X   ARGV-element, is returned in `optarg'.  Two colons mean an option that
  10738. X   wants an optional arg; if there is text in the current ARGV-element,
  10739. X   it is returned in `optarg', otherwise `optarg' is set to zero.
  10740. X
  10741. X   If OPTSTRING starts with `-' or `+', it requests different methods of
  10742. X   handling the non-option ARGV-elements.
  10743. X   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
  10744. X
  10745. X   Long-named options begin with `--' instead of `-'.
  10746. X   Their names may be abbreviated as long as the abbreviation is unique
  10747. X   or is an exact match for some defined option.  If they have an
  10748. X   argument, it follows the option name in the same ARGV-element, separated
  10749. X   from the option name by a `=', or else the in next ARGV-element.
  10750. X   When `getopt' finds a long-named option, it returns 0 if that option's
  10751. X   `flag' field is nonzero, the value of the option's `val' field
  10752. X   if the `flag' field is zero.
  10753. X
  10754. X   The elements of ARGV aren't really const, because we permute them.
  10755. X   But we pretend they're const in the prototype to be compatible
  10756. X   with other systems.
  10757. X
  10758. X   LONGOPTS is a vector of `struct option' terminated by an
  10759. X   element containing a name which is zero.
  10760. X
  10761. X   LONGIND returns the index in LONGOPT of the long-named option found.
  10762. X   It is only valid when a long-named option has been found by the most
  10763. X   recent call.
  10764. X
  10765. X   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
  10766. X   long-named options.  */
  10767. X
  10768. Xint
  10769. X_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
  10770. X     int argc;
  10771. X     char *const *argv;
  10772. X     const char *optstring;
  10773. X     const struct option *longopts;
  10774. X     int *longind;
  10775. X     int long_only;
  10776. X{
  10777. X  int option_index;
  10778. X
  10779. X  optarg = 0;
  10780. X
  10781. X  /* Initialize the internal data when the first call is made.
  10782. X     Start processing options with ARGV-element 1 (since ARGV-element 0
  10783. X     is the program name); the sequence of previously skipped
  10784. X     non-option ARGV-elements is empty.  */
  10785. X
  10786. X  if (optind == 0)
  10787. X    {
  10788. X      first_nonopt = last_nonopt = optind = 1;
  10789. X
  10790. X      nextchar = NULL;
  10791. X
  10792. X      /* Determine how to handle the ordering of options and nonoptions.  */
  10793. X
  10794. X      if (optstring[0] == '-')
  10795. X    {
  10796. X      ordering = RETURN_IN_ORDER;
  10797. X      ++optstring;
  10798. X    }
  10799. X      else if (optstring[0] == '+')
  10800. X    {
  10801. X      ordering = REQUIRE_ORDER;
  10802. X      ++optstring;
  10803. X    }
  10804. X      else if (getenv ("POSIXLY_CORRECT") != NULL)
  10805. X    ordering = REQUIRE_ORDER;
  10806. X      else
  10807. X    ordering = PERMUTE;
  10808. X    }
  10809. X
  10810. X  if (nextchar == NULL || *nextchar == '\0')
  10811. X    {
  10812. X      if (ordering == PERMUTE)
  10813. X    {
  10814. X      /* If we have just processed some options following some non-options,
  10815. X         exchange them so that the options come first.  */
  10816. X
  10817. X      if (first_nonopt != last_nonopt && last_nonopt != optind)
  10818. X        exchange ((char **) argv);
  10819. X      else if (last_nonopt != optind)
  10820. X        first_nonopt = optind;
  10821. X
  10822. X      /* Now skip any additional non-options
  10823. X         and extend the range of non-options previously skipped.  */
  10824. X
  10825. X      while (optind < argc
  10826. X         && (argv[optind][0] != '-' || argv[optind][1] == '\0')
  10827. X#ifdef GETOPT_COMPAT
  10828. X         && (longopts == NULL
  10829. X             || argv[optind][0] != '+' || argv[optind][1] == '\0')
  10830. X#endif                /* GETOPT_COMPAT */
  10831. X         )
  10832. X        optind++;
  10833. X      last_nonopt = optind;
  10834. X    }
  10835. X
  10836. X      /* Special ARGV-element `--' means premature end of options.
  10837. X     Skip it like a null option,
  10838. X     then exchange with previous non-options as if it were an option,
  10839. X     then skip everything else like a non-option.  */
  10840. X
  10841. X      if (optind != argc && !strcmp (argv[optind], "--"))
  10842. X    {
  10843. X      optind++;
  10844. X
  10845. X      if (first_nonopt != last_nonopt && last_nonopt != optind)
  10846. X        exchange ((char **) argv);
  10847. X      else if (first_nonopt == last_nonopt)
  10848. X        first_nonopt = optind;
  10849. X      last_nonopt = argc;
  10850. X
  10851. X      optind = argc;
  10852. X    }
  10853. X
  10854. X      /* If we have done all the ARGV-elements, stop the scan
  10855. X     and back over any non-options that we skipped and permuted.  */
  10856. X
  10857. X      if (optind == argc)
  10858. X    {
  10859. X      /* Set the next-arg-index to point at the non-options
  10860. X         that we previously skipped, so the caller will digest them.  */
  10861. X      if (first_nonopt != last_nonopt)
  10862. X        optind = first_nonopt;
  10863. X      return EOF;
  10864. X    }
  10865. X
  10866. X      /* If we have come to a non-option and did not permute it,
  10867. X     either stop the scan or describe it to the caller and pass it by.  */
  10868. X
  10869. X      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
  10870. X#ifdef GETOPT_COMPAT
  10871. X      && (longopts == NULL
  10872. X          || argv[optind][0] != '+' || argv[optind][1] == '\0')
  10873. X#endif                /* GETOPT_COMPAT */
  10874. X      )
  10875. X    {
  10876. X      if (ordering == REQUIRE_ORDER)
  10877. X        return EOF;
  10878. X      optarg = argv[optind++];
  10879. X      return 1;
  10880. X    }
  10881. X
  10882. X      /* We have found another option-ARGV-element.
  10883. X     Start decoding its characters.  */
  10884. X
  10885. X      nextchar = (argv[optind] + 1
  10886. X          + (longopts != NULL && argv[optind][1] == '-'));
  10887. X    }
  10888. X
  10889. X  if (longopts != NULL
  10890. X      && ((argv[optind][0] == '-'
  10891. X       && (argv[optind][1] == '-' || long_only))
  10892. X#ifdef GETOPT_COMPAT
  10893. X      || argv[optind][0] == '+'
  10894. X#endif                /* GETOPT_COMPAT */
  10895. X      ))
  10896. X    {
  10897. X      const struct option *p;
  10898. X      char *s = nextchar;
  10899. X      int exact = 0;
  10900. X      int ambig = 0;
  10901. X      const struct option *pfound = NULL;
  10902. X      int indfound;
  10903. X
  10904. X      while (*s && *s != '=')
  10905. X    s++;
  10906. X
  10907. X      /* Test all options for either exact match or abbreviated matches.  */
  10908. X      for (p = longopts, option_index = 0; p->name;
  10909. X       p++, option_index++)
  10910. X    if (!strncmp (p->name, nextchar, s - nextchar))
  10911. X      {
  10912. X        if (s - nextchar == strlen (p->name))
  10913. X          {
  10914. X        /* Exact match found.  */
  10915. X        pfound = p;
  10916. X        indfound = option_index;
  10917. X        exact = 1;
  10918. X        break;
  10919. X          }
  10920. X        else if (pfound == NULL)
  10921. X          {
  10922. X        /* First nonexact match found.  */
  10923. X        pfound = p;
  10924. X        indfound = option_index;
  10925. X          }
  10926. X        else
  10927. X          /* Second nonexact match found.  */
  10928. X          ambig = 1;
  10929. X      }
  10930. X
  10931. X      if (ambig && !exact)
  10932. X    {
  10933. X      if (opterr)
  10934. X        fprintf (stderr, "%s: option `%s' is ambiguous\n",
  10935. X             argv[0], argv[optind]);
  10936. X      nextchar += strlen (nextchar);
  10937. X      optind++;
  10938. X      return '?';
  10939. X    }
  10940. X
  10941. X      if (pfound != NULL)
  10942. X    {
  10943. X      option_index = indfound;
  10944. X      optind++;
  10945. X      if (*s)
  10946. X        {
  10947. X          /* Don't test has_arg with >, because some C compilers don't
  10948. X         allow it to be used on enums.  */
  10949. X          if (pfound->has_arg)
  10950. X        optarg = s + 1;
  10951. X          else
  10952. X        {
  10953. X          if (opterr)
  10954. X            {
  10955. X              if (argv[optind - 1][1] == '-')
  10956. X            /* --option */
  10957. X            fprintf (stderr,
  10958. X                 "%s: option `--%s' doesn't allow an argument\n",
  10959. X                 argv[0], pfound->name);
  10960. X              else
  10961. X            /* +option or -option */
  10962. X            fprintf (stderr,
  10963. X                 "%s: option `%c%s' doesn't allow an argument\n",
  10964. X                 argv[0], argv[optind - 1][0], pfound->name);
  10965. X            }
  10966. X          nextchar += strlen (nextchar);
  10967. X          return '?';
  10968. X        }
  10969. X        }
  10970. X      else if (pfound->has_arg == 1)
  10971. X        {
  10972. X          if (optind < argc)
  10973. X        optarg = argv[optind++];
  10974. X          else
  10975. X        {
  10976. X          if (opterr)
  10977. X            fprintf (stderr, "%s: option `%s' requires an argument\n",
  10978. X                 argv[0], argv[optind - 1]);
  10979. X          nextchar += strlen (nextchar);
  10980. X          return optstring[0] == ':' ? ':' : '?';
  10981. X        }
  10982. X        }
  10983. X      nextchar += strlen (nextchar);
  10984. X      if (longind != NULL)
  10985. X        *longind = option_index;
  10986. X      if (pfound->flag)
  10987. X        {
  10988. X          *(pfound->flag) = pfound->val;
  10989. X          return 0;
  10990. X        }
  10991. X      return pfound->val;
  10992. X    }
  10993. X      /* Can't find it as a long option.  If this is not getopt_long_only,
  10994. X     or the option starts with '--' or is not a valid short
  10995. X     option, then it's an error.
  10996. X     Otherwise interpret it as a short option.  */
  10997. X      if (!long_only || argv[optind][1] == '-'
  10998. X#ifdef GETOPT_COMPAT
  10999. X      || argv[optind][0] == '+'
  11000. X#endif                /* GETOPT_COMPAT */
  11001. X      || my_index (optstring, *nextchar) == NULL)
  11002. X    {
  11003. X      if (opterr)
  11004. X        {
  11005. X          if (argv[optind][1] == '-')
  11006. X        /* --option */
  11007. X        fprintf (stderr, "%s: unrecognized option `--%s'\n",
  11008. X             argv[0], nextchar);
  11009. X          else
  11010. X        /* +option or -option */
  11011. X        fprintf (stderr, "%s: unrecognized option `%c%s'\n",
  11012. X             argv[0], argv[optind][0], nextchar);
  11013. X        }
  11014. X      nextchar = (char *) "";
  11015. X      optind++;
  11016. X      return '?';
  11017. X    }
  11018. X    }
  11019. X
  11020. X  /* Look at and handle the next option-character.  */
  11021. X
  11022. X  {
  11023. X    char c = *nextchar++;
  11024. X    char *temp = my_index (optstring, c);
  11025. X
  11026. X    /* Increment `optind' when we start to process its last character.  */
  11027. X    if (*nextchar == '\0')
  11028. X      ++optind;
  11029. X
  11030. X    if (temp == NULL || c == ':')
  11031. X      {
  11032. X    if (opterr)
  11033. X      {
  11034. X#if 0
  11035. X        if (c < 040 || c >= 0177)
  11036. X          fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
  11037. X               argv[0], c);
  11038. X        else
  11039. X          fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
  11040. X#else
  11041. X        /* 1003.2 specifies the format of this message.  */
  11042. X        fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
  11043. X#endif
  11044. X      }
  11045. X    optopt = c;
  11046. X    return '?';
  11047. X      }
  11048. X    if (temp[1] == ':')
  11049. X      {
  11050. X    if (temp[2] == ':')
  11051. X      {
  11052. X        /* This is an option that accepts an argument optionally.  */
  11053. X        if (*nextchar != '\0')
  11054. X          {
  11055. X        optarg = nextchar;
  11056. X        optind++;
  11057. X          }
  11058. X        else
  11059. X          optarg = 0;
  11060. X        nextchar = NULL;
  11061. X      }
  11062. X    else
  11063. X      {
  11064. X        /* This is an option that requires an argument.  */
  11065. X        if (*nextchar != '\0')
  11066. X          {
  11067. X        optarg = nextchar;
  11068. X        /* If we end this ARGV-element by taking the rest as an arg,
  11069. X           we must advance to the next element now.  */
  11070. X        optind++;
  11071. X          }
  11072. X        else if (optind == argc)
  11073. X          {
  11074. X        if (opterr)
  11075. X          {
  11076. X#if 0
  11077. X            fprintf (stderr, "%s: option `-%c' requires an argument\n",
  11078. X                 argv[0], c);
  11079. X#else
  11080. X            /* 1003.2 specifies the format of this message.  */
  11081. X            fprintf (stderr, "%s: option requires an argument -- %c\n",
  11082. X                 argv[0], c);
  11083. X#endif
  11084. X          }
  11085. X        optopt = c;
  11086. X        if (optstring[0] == ':')
  11087. X          c = ':';
  11088. X        else
  11089. X          c = '?';
  11090. X          }
  11091. X        else
  11092. X          /* We already incremented `optind' once;
  11093. X         increment it again when taking next ARGV-elt as argument.  */
  11094. X          optarg = argv[optind++];
  11095. X        nextchar = NULL;
  11096. X      }
  11097. X      }
  11098. X    return c;
  11099. X  }
  11100. X}
  11101. X
  11102. Xint
  11103. Xgetopt (argc, argv, optstring)
  11104. X     int argc;
  11105. X     char *const *argv;
  11106. X     const char *optstring;
  11107. X{
  11108. X  return _getopt_internal (argc, argv, optstring,
  11109. X               (const struct option *) 0,
  11110. X               (int *) 0,
  11111. X               0);
  11112. X}
  11113. X
  11114. X#ifdef TEST
  11115. X
  11116. X/* Compile with -DTEST to make an executable for use in testing
  11117. X   the above definition of `getopt'.  */
  11118. X
  11119. Xint
  11120. Xmain (argc, argv)
  11121. X     int argc;
  11122. X     char **argv;
  11123. X{
  11124. X  int c;
  11125. X  int digit_optind = 0;
  11126. X
  11127. X  while (1)
  11128. X    {
  11129. X      int this_option_optind = optind ? optind : 1;
  11130. X
  11131. X      c = getopt (argc, argv, "abc:d:0123456789");
  11132. X      if (c == EOF)
  11133. X    break;
  11134. X
  11135. X      switch (c)
  11136. X    {
  11137. X    case '0':
  11138. X    case '1':
  11139. X    case '2':
  11140. X    case '3':
  11141. X    case '4':
  11142. X    case '5':
  11143. X    case '6':
  11144. X    case '7':
  11145. X    case '8':
  11146. X    case '9':
  11147. X      if (digit_optind != 0 && digit_optind != this_option_optind)
  11148. X        printf ("digits occur in two different argv-elements.\n");
  11149. X      digit_optind = this_option_optind;
  11150. X      printf ("option %c\n", c);
  11151. X      break;
  11152. X
  11153. X    case 'a':
  11154. X      printf ("option a\n");
  11155. X      break;
  11156. X
  11157. X    case 'b':
  11158. X      printf ("option b\n");
  11159. X      break;
  11160. X
  11161. X    case 'c':
  11162. X      printf ("option c with value `%s'\n", optarg);
  11163. X      break;
  11164. X
  11165. X    case '?':
  11166. X      break;
  11167. X
  11168. X    default:
  11169. X      printf ("?? getopt returned character code 0%o ??\n", c);
  11170. X    }
  11171. X    }
  11172. X
  11173. X  if (optind < argc)
  11174. X    {
  11175. X      printf ("non-option ARGV-elements: ");
  11176. X      while (optind < argc)
  11177. X    printf ("%s ", argv[optind++]);
  11178. X      printf ("\n");
  11179. X    }
  11180. X
  11181. X  exit (0);
  11182. X}
  11183. X
  11184. X#endif /* TEST */
  11185. END_OF_FILE
  11186. if test 20137 -ne `wc -c <'getopt.c'`; then
  11187.     echo shar: \"'getopt.c'\" unpacked with wrong size!
  11188. fi
  11189. # end of 'getopt.c'
  11190. fi
  11191. if test -f 'malloc.c' -a "${1}" != "-c" ; then 
  11192.   echo shar: Will not clobber existing file \"'malloc.c'\"
  11193. else
  11194. echo shar: Extracting \"'malloc.c'\" \(30710 characters\)
  11195. sed "s/^X//" >'malloc.c' <<'END_OF_FILE'
  11196. X/* DO NOT EDIT THIS FILE -- it is automagically generated.  -*- C -*- */
  11197. X
  11198. X#define _MALLOC_INTERNAL
  11199. X
  11200. X/* The malloc headers and source files from the C library follow here.  */
  11201. X
  11202. X/* Declarations for `malloc' and friends.
  11203. X   Copyright 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
  11204. X          Written May 1989 by Mike Haertel.
  11205. X
  11206. XThis library is free software; you can redistribute it and/or
  11207. Xmodify it under the terms of the GNU Library General Public License as
  11208. Xpublished by the Free Software Foundation; either version 2 of the
  11209. XLicense, or (at your option) any later version.
  11210. X
  11211. XThis library is distributed in the hope that it will be useful,
  11212. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  11213. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11214. XLibrary General Public License for more details.
  11215. X
  11216. XYou should have received a copy of the GNU Library General Public
  11217. XLicense along with this library; see the file COPYING.LIB.  If
  11218. Xnot, write to the Free Software Foundation, Inc., 675 Mass Ave,
  11219. XCambridge, MA 02139, USA.
  11220. X
  11221. X   The author may be reached (Email) at the address mike@ai.mit.edu,
  11222. X   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
  11223. X
  11224. X#ifndef _MALLOC_H
  11225. X
  11226. X#define _MALLOC_H    1
  11227. X
  11228. X#ifdef _MALLOC_INTERNAL
  11229. X/* Harmless, gets __GNU_LIBRARY__ defined.
  11230. X   We must do this before #defining size_t and ptrdiff_t
  11231. X   because <stdio.h> tries to typedef them on some systems.  */
  11232. X#include <stdio.h>
  11233. X#endif
  11234. X
  11235. X#ifdef    __cplusplus
  11236. Xextern "C"
  11237. X{
  11238. X#endif
  11239. X
  11240. X#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
  11241. X#undef    __P
  11242. X#define    __P(args)    args
  11243. X#undef    __ptr_t
  11244. X#define    __ptr_t        void *
  11245. X#else /* Not C++ or ANSI C.  */
  11246. X#undef    __P
  11247. X#define    __P(args)    ()
  11248. X#undef    const
  11249. X#define    const
  11250. X#undef    __ptr_t
  11251. X#define    __ptr_t        char *
  11252. X#endif /* C++ or ANSI C.  */
  11253. X
  11254. X#ifndef    NULL
  11255. X#define    NULL    0
  11256. X#endif
  11257. X
  11258. X#ifdef    __STDC__
  11259. X#include <stddef.h>
  11260. X#else
  11261. X#undef    size_t
  11262. X#define    size_t        unsigned int
  11263. X#undef    ptrdiff_t
  11264. X#define    ptrdiff_t    int
  11265. X#endif
  11266. X
  11267. X
  11268. X/* Allocate SIZE bytes of memory.  */
  11269. Xextern __ptr_t malloc __P ((size_t __size));
  11270. X/* Re-allocate the previously allocated block
  11271. X   in __ptr_t, making the new block SIZE bytes long.  */
  11272. Xextern __ptr_t realloc __P ((__ptr_t __ptr, size_t __size));
  11273. X/* Allocate NMEMB elements of SIZE bytes each, all initialized to 0.  */
  11274. Xextern __ptr_t calloc __P ((size_t __nmemb, size_t __size));
  11275. X/* Free a block allocated by `malloc', `realloc' or `calloc'.  */
  11276. Xextern void free __P ((__ptr_t __ptr));
  11277. X
  11278. X/* Allocate SIZE bytes allocated to ALIGNMENT bytes.  */
  11279. Xextern __ptr_t memalign __P ((size_t __alignment, size_t __size));
  11280. X
  11281. X/* Allocate SIZE bytes on a page boundary.  */
  11282. Xextern __ptr_t valloc __P ((size_t __size));
  11283. X
  11284. X
  11285. X#ifdef _MALLOC_INTERNAL
  11286. X
  11287. X#ifdef    HAVE_CONFIG_H
  11288. X#include "config.h"
  11289. X#endif
  11290. X
  11291. X#if    defined(__GNU_LIBRARY__) || defined(STDC_HEADERS) || defined(USG)
  11292. X#include <string.h>
  11293. X#else
  11294. X#ifndef memset
  11295. X#define    memset(s, zero, n)    bzero ((s), (n))
  11296. X#endif
  11297. X#ifndef memcpy
  11298. X#define    memcpy(d, s, n)        bcopy ((s), (d), (n))
  11299. X#endif
  11300. X#ifndef memmove
  11301. X#define    memmove(d, s, n)    bcopy ((s), (d), (n))
  11302. X#endif
  11303. X#endif
  11304. X
  11305. X
  11306. X#if    defined(__GNU_LIBRARY__) || defined(__STDC__)
  11307. X#include <limits.h>
  11308. X#else
  11309. X#define    CHAR_BIT    8
  11310. X#endif
  11311. X
  11312. X/* The allocator divides the heap into blocks of fixed size; large
  11313. X   requests receive one or more whole blocks, and small requests
  11314. X   receive a fragment of a block.  Fragment sizes are powers of two,
  11315. X   and all fragments of a block are the same size.  When all the
  11316. X   fragments in a block have been freed, the block itself is freed.  */
  11317. X#define INT_BIT        (CHAR_BIT * sizeof(int))
  11318. X#define BLOCKLOG    (INT_BIT > 16 ? 12 : 9)
  11319. X#define BLOCKSIZE    (1 << BLOCKLOG)
  11320. X#define BLOCKIFY(SIZE)    (((SIZE) + BLOCKSIZE - 1) / BLOCKSIZE)
  11321. X
  11322. X/* Determine the amount of memory spanned by the initial heap table
  11323. X   (not an absolute limit).  */
  11324. X#define HEAP        (INT_BIT > 16 ? 4194304 : 65536)
  11325. X
  11326. X/* Number of contiguous free blocks allowed to build up at the end of
  11327. X   memory before they will be returned to the system.  */
  11328. X#define FINAL_FREE_BLOCKS    8
  11329. X
  11330. X/* Where to start searching the free list when looking for new memory.
  11331. X   The two possible values are 0 and _heapindex.  Starting at 0 seems
  11332. X   to reduce total memory usage, while starting at _heapindex seems to
  11333. X   run faster.  */
  11334. X#define MALLOC_SEARCH_START    _heapindex
  11335. X
  11336. X/* Data structure giving per-block information.  */
  11337. Xtypedef union
  11338. X  {
  11339. X    /* Heap information for a busy block.  */
  11340. X    struct
  11341. X      {
  11342. X    /* Zero for a large block, or positive giving the
  11343. X       logarithm to the base two of the fragment size.  */
  11344. X    int type;
  11345. X    union
  11346. X      {
  11347. X        struct
  11348. X          {
  11349. X        size_t nfree;    /* Free fragments in a fragmented block.  */
  11350. X        size_t first;    /* First free fragment of the block.  */
  11351. X          } frag;
  11352. X        /* Size (in blocks) of a large cluster.  */
  11353. X        size_t size;
  11354. X      } info;
  11355. X      } busy;
  11356. X    /* Heap information for a free block
  11357. X       (that may be the first of a free cluster).  */
  11358. X    struct
  11359. X      {
  11360. X    size_t size;        /* Size (in blocks) of a free cluster.  */
  11361. X    size_t next;        /* Index of next free cluster.  */
  11362. X    size_t prev;        /* Index of previous free cluster.  */
  11363. X      } free;
  11364. X  } malloc_info;
  11365. X
  11366. X/* Pointer to first block of the heap.  */
  11367. Xextern char *_heapbase;
  11368. X
  11369. X/* Table indexed by block number giving per-block information.  */
  11370. Xextern malloc_info *_heapinfo;
  11371. X
  11372. X/* Address to block number and vice versa.  */
  11373. X#define BLOCK(A)    (((char *) (A) - _heapbase) / BLOCKSIZE + 1)
  11374. X#define ADDRESS(B)    ((__ptr_t) (((B) - 1) * BLOCKSIZE + _heapbase))
  11375. X
  11376. X/* Current search index for the heap table.  */
  11377. Xextern size_t _heapindex;
  11378. X
  11379. X/* Limit of valid info table indices.  */
  11380. Xextern size_t _heaplimit;
  11381. X
  11382. X/* Doubly linked lists of free fragments.  */
  11383. Xstruct list
  11384. X  {
  11385. X    struct list *next;
  11386. X    struct list *prev;
  11387. X  };
  11388. X
  11389. X/* Free list headers for each fragment size.  */
  11390. Xextern struct list _fraghead[];
  11391. X
  11392. X/* List of blocks allocated with `memalign' (or `valloc').  */
  11393. Xstruct alignlist
  11394. X  {
  11395. X    struct alignlist *next;
  11396. X    __ptr_t aligned;        /* The address that memaligned returned.  */
  11397. X    __ptr_t exact;        /* The address that malloc returned.  */
  11398. X  };
  11399. Xextern struct alignlist *_aligned_blocks;
  11400. X
  11401. X/* Instrumentation.  */
  11402. Xextern size_t _chunks_used;
  11403. Xextern size_t _bytes_used;
  11404. Xextern size_t _chunks_free;
  11405. Xextern size_t _bytes_free;
  11406. X
  11407. X/* Internal version of `free' used in `morecore' (malloc.c). */
  11408. Xextern void _free_internal __P ((__ptr_t __ptr));
  11409. X
  11410. X#endif /* _MALLOC_INTERNAL.  */
  11411. X
  11412. X/* Underlying allocation function; successive calls should
  11413. X   return contiguous pieces of memory.  */
  11414. Xextern __ptr_t (*__morecore) __P ((ptrdiff_t __size));
  11415. X
  11416. X/* Default value of `__morecore'.  */
  11417. Xextern __ptr_t __default_morecore __P ((ptrdiff_t __size));
  11418. X
  11419. X/* If not NULL, this function is called after each time
  11420. X   `__morecore' is called to increase the data size.  */
  11421. Xextern void (*__after_morecore_hook) __P ((void));
  11422. X
  11423. X/* Nonzero if `malloc' has been called and done its initialization.  */
  11424. Xextern int __malloc_initialized;
  11425. X
  11426. X/* Hooks for debugging versions.  */
  11427. Xextern void (*__free_hook) __P ((__ptr_t __ptr));
  11428. Xextern __ptr_t (*__malloc_hook) __P ((size_t __size));
  11429. Xextern __ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
  11430. X
  11431. X/* Activate a standard collection of debugging hooks.  */
  11432. Xextern int mcheck __P ((void (*__func) __P ((void))));
  11433. X
  11434. X/* Activate a standard collection of tracing hooks.  */
  11435. Xextern void mtrace __P ((void));
  11436. X
  11437. X/* Statistics available to the user.  */
  11438. Xstruct mstats
  11439. X  {
  11440. X    size_t bytes_total;        /* Total size of the heap. */
  11441. X    size_t chunks_used;        /* Chunks allocated by the user. */
  11442. X    size_t bytes_used;        /* Byte total of user-allocated chunks. */
  11443. X    size_t chunks_free;        /* Chunks in the free list. */
  11444. X    size_t bytes_free;        /* Byte total of chunks in the free list. */
  11445. X  };
  11446. X
  11447. X/* Pick up the current statistics. */
  11448. Xextern struct mstats mstats __P ((void));
  11449. X
  11450. X/* Call WARNFUN with a warning message when memory usage is high.  */
  11451. Xextern void memory_warnings __P ((__ptr_t __start,
  11452. X                  void (*__warnfun) __P ((__const char *))));
  11453. X
  11454. X
  11455. X/* Relocating allocator.  */
  11456. X
  11457. X/* Allocate SIZE bytes, and store the address in *HANDLEPTR.  */
  11458. Xextern __ptr_t r_alloc __P ((__ptr_t *__handleptr, size_t __size));
  11459. X
  11460. X/* Free the storage allocated in HANDLEPTR.  */
  11461. Xextern void r_alloc_free __P ((__ptr_t *__handleptr));
  11462. X
  11463. X/* Adjust the block at HANDLEPTR to be SIZE bytes long.  */
  11464. Xextern __ptr_t r_re_alloc __P ((__ptr_t *__handleptr, size_t __size));
  11465. X
  11466. X
  11467. X#ifdef    __cplusplus
  11468. X}
  11469. X#endif
  11470. X
  11471. X#endif /* malloc.h  */
  11472. X/* Memory allocator `malloc'.
  11473. X   Copyright 1990, 1991, 1992 Free Software Foundation
  11474. X          Written May 1989 by Mike Haertel.
  11475. X
  11476. XThis library is free software; you can redistribute it and/or
  11477. Xmodify it under the terms of the GNU Library General Public License as
  11478. Xpublished by the Free Software Foundation; either version 2 of the
  11479. XLicense, or (at your option) any later version.
  11480. X
  11481. XThis library is distributed in the hope that it will be useful,
  11482. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  11483. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11484. XLibrary General Public License for more details.
  11485. X
  11486. XYou should have received a copy of the GNU Library General Public
  11487. XLicense along with this library; see the file COPYING.LIB.  If
  11488. Xnot, write to the Free Software Foundation, Inc., 675 Mass Ave,
  11489. XCambridge, MA 02139, USA.
  11490. X
  11491. X   The author may be reached (Email) at the address mike@ai.mit.edu,
  11492. X   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
  11493. X
  11494. X#ifndef    _MALLOC_INTERNAL
  11495. X#define _MALLOC_INTERNAL
  11496. X#include <malloc.h>
  11497. X#endif
  11498. X
  11499. X/* How to really get more memory.  */
  11500. X__ptr_t (*__morecore) __P ((ptrdiff_t __size)) = __default_morecore;
  11501. X
  11502. X/* Debugging hook for `malloc'.  */
  11503. X__ptr_t (*__malloc_hook) __P ((size_t __size));
  11504. X
  11505. X/* Pointer to the base of the first block.  */
  11506. Xchar *_heapbase;
  11507. X
  11508. X/* Block information table.  Allocated with align/__free (not malloc/free).  */
  11509. Xmalloc_info *_heapinfo;
  11510. X
  11511. X/* Number of info entries.  */
  11512. Xstatic size_t heapsize;
  11513. X
  11514. X/* Search index in the info table.  */
  11515. Xsize_t _heapindex;
  11516. X
  11517. X/* Limit of valid info table indices.  */
  11518. Xsize_t _heaplimit;
  11519. X
  11520. X/* Free lists for each fragment size.  */
  11521. Xstruct list _fraghead[BLOCKLOG];
  11522. X
  11523. X/* Instrumentation.  */
  11524. Xsize_t _chunks_used;
  11525. Xsize_t _bytes_used;
  11526. Xsize_t _chunks_free;
  11527. Xsize_t _bytes_free;
  11528. X
  11529. X/* Are you experienced?  */
  11530. Xint __malloc_initialized;
  11531. X
  11532. Xvoid (*__after_morecore_hook) __P ((void));
  11533. X
  11534. X/* Aligned allocation.  */
  11535. Xstatic __ptr_t align __P ((size_t));
  11536. Xstatic __ptr_t
  11537. Xalign (size)
  11538. X     size_t size;
  11539. X{
  11540. X  __ptr_t result;
  11541. X  unsigned long int adj;
  11542. X
  11543. X  result = (*__morecore) (size);
  11544. X  adj = (unsigned long int) ((unsigned long int) ((char *) result -
  11545. X                        (char *) NULL)) % BLOCKSIZE;
  11546. X  if (adj != 0)
  11547. X    {
  11548. X      adj = BLOCKSIZE - adj;
  11549. X      (void) (*__morecore) (adj);
  11550. X      result = (char *) result + adj;
  11551. X    }
  11552. X
  11553. X  if (__after_morecore_hook)
  11554. X    (*__after_morecore_hook) ();
  11555. X
  11556. X  return result;
  11557. X}
  11558. X
  11559. X/* Set everything up and remember that we have.  */
  11560. Xstatic int initialize __P ((void));
  11561. Xstatic int
  11562. Xinitialize ()
  11563. X{
  11564. X  heapsize = HEAP / BLOCKSIZE;
  11565. X  _heapinfo = (malloc_info *) align (heapsize * sizeof (malloc_info));
  11566. X  if (_heapinfo == NULL)
  11567. X    return 0;
  11568. X  memset (_heapinfo, 0, heapsize * sizeof (malloc_info));
  11569. X  _heapinfo[0].free.size = 0;
  11570. X  _heapinfo[0].free.next = _heapinfo[0].free.prev = 0;
  11571. X  _heapindex = 0;
  11572. X  _heapbase = (char *) _heapinfo;
  11573. X  __malloc_initialized = 1;
  11574. X  return 1;
  11575. X}
  11576. X
  11577. X/* Get neatly aligned memory, initializing or
  11578. X   growing the heap info table as necessary. */
  11579. Xstatic __ptr_t morecore __P ((size_t));
  11580. Xstatic __ptr_t
  11581. Xmorecore (size)
  11582. X     size_t size;
  11583. X{
  11584. X  __ptr_t result;
  11585. X  malloc_info *newinfo, *oldinfo;
  11586. X  size_t newsize;
  11587. X
  11588. X  result = align (size);
  11589. X  if (result == NULL)
  11590. X    return NULL;
  11591. X
  11592. X  /* Check if we need to grow the info table.  */
  11593. X  if ((size_t) BLOCK ((char *) result + size) > heapsize)
  11594. X    {
  11595. X      newsize = heapsize;
  11596. X      while ((size_t) BLOCK ((char *) result + size) > newsize)
  11597. X    newsize *= 2;
  11598. X      newinfo = (malloc_info *) align (newsize * sizeof (malloc_info));
  11599. X      if (newinfo == NULL)
  11600. X    {
  11601. X      (*__morecore) (-size);
  11602. X      return NULL;
  11603. X    }
  11604. X      memset (newinfo, 0, newsize * sizeof (malloc_info));
  11605. X      memcpy (newinfo, _heapinfo, heapsize * sizeof (malloc_info));
  11606. X      oldinfo = _heapinfo;
  11607. X      newinfo[BLOCK (oldinfo)].busy.type = 0;
  11608. X      newinfo[BLOCK (oldinfo)].busy.info.size
  11609. X    = BLOCKIFY (heapsize * sizeof (malloc_info));
  11610. X      _heapinfo = newinfo;
  11611. X      _free_internal (oldinfo);
  11612. X      heapsize = newsize;
  11613. X    }
  11614. X
  11615. X  _heaplimit = BLOCK ((char *) result + size);
  11616. X  return result;
  11617. X}
  11618. X
  11619. X/* Allocate memory from the heap.  */
  11620. X__ptr_t
  11621. Xmalloc (size)
  11622. X     size_t size;
  11623. X{
  11624. X  __ptr_t result;
  11625. X  size_t block, blocks, lastblocks, start;
  11626. X  register size_t i;
  11627. X  struct list *next;
  11628. X
  11629. X  if (size == 0)
  11630. X    return NULL;
  11631. X
  11632. X  if (__malloc_hook != NULL)
  11633. X    return (*__malloc_hook) (size);
  11634. X
  11635. X  if (!__malloc_initialized)
  11636. X    if (!initialize ())
  11637. X      return NULL;
  11638. X
  11639. X  if (size < sizeof (struct list))
  11640. X      size = sizeof (struct list);
  11641. X
  11642. X  /* Determine the allocation policy based on the request size.  */
  11643. X  if (size <= BLOCKSIZE / 2)
  11644. X    {
  11645. X      /* Small allocation to receive a fragment of a block.
  11646. X     Determine the logarithm to base two of the fragment size. */
  11647. X      register size_t log = 1;
  11648. X      --size;
  11649. X      while ((size /= 2) != 0)
  11650. X    ++log;
  11651. X
  11652. X      /* Look in the fragment lists for a
  11653. X     free fragment of the desired size. */
  11654. X      next = _fraghead[log].next;
  11655. X      if (next != NULL)
  11656. X    {
  11657. X      /* There are free fragments of this size.
  11658. X         Pop a fragment out of the fragment list and return it.
  11659. X         Update the block's nfree and first counters. */
  11660. X      result = (__ptr_t) next;
  11661. X      next->prev->next = next->next;
  11662. X      if (next->next != NULL)
  11663. X        next->next->prev = next->prev;
  11664. X      block = BLOCK (result);
  11665. X      if (--_heapinfo[block].busy.info.frag.nfree != 0)
  11666. X        _heapinfo[block].busy.info.frag.first = (unsigned long int)
  11667. X          ((unsigned long int) ((char *) next->next - (char *) NULL)
  11668. X           % BLOCKSIZE) >> log;
  11669. X
  11670. X      /* Update the statistics.  */
  11671. X      ++_chunks_used;
  11672. X      _bytes_used += 1 << log;
  11673. X      --_chunks_free;
  11674. X      _bytes_free -= 1 << log;
  11675. X    }
  11676. X      else
  11677. X    {
  11678. X      /* No free fragments of the desired size, so get a new block
  11679. X         and break it into fragments, returning the first.  */
  11680. X      result = malloc (BLOCKSIZE);
  11681. X      if (result == NULL)
  11682. X        return NULL;
  11683. X
  11684. X      /* Link all fragments but the first into the free list.  */
  11685. X      for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
  11686. X        {
  11687. X          next = (struct list *) ((char *) result + (i << log));
  11688. X          next->next = _fraghead[log].next;
  11689. X          next->prev = &_fraghead[log];
  11690. X          next->prev->next = next;
  11691. X          if (next->next != NULL)
  11692. X        next->next->prev = next;
  11693. X        }
  11694. X
  11695. X      /* Initialize the nfree and first counters for this block.  */
  11696. X      block = BLOCK (result);
  11697. X      _heapinfo[block].busy.type = log;
  11698. X      _heapinfo[block].busy.info.frag.nfree = i - 1;
  11699. X      _heapinfo[block].busy.info.frag.first = i - 1;
  11700. X
  11701. X      _chunks_free += (BLOCKSIZE >> log) - 1;
  11702. X      _bytes_free += BLOCKSIZE - (1 << log);
  11703. X      _bytes_used -= BLOCKSIZE - (1 << log);
  11704. X    }
  11705. X    }
  11706. X  else
  11707. X    {
  11708. X      /* Large allocation to receive one or more blocks.
  11709. X     Search the free list in a circle starting at the last place visited.
  11710. X     If we loop completely around without finding a large enough
  11711. X     space we will have to get more memory from the system.  */
  11712. X      blocks = BLOCKIFY (size);
  11713. X      start = block = MALLOC_SEARCH_START;
  11714. X      while (_heapinfo[block].free.size < blocks)
  11715. X    {
  11716. X      block = _heapinfo[block].free.next;
  11717. X      if (block == start)
  11718. X        {
  11719. X          /* Need to get more from the system.  Check to see if
  11720. X         the new core will be contiguous with the final free
  11721. X         block; if so we don't need to get as much.  */
  11722. X          block = _heapinfo[0].free.prev;
  11723. X          lastblocks = _heapinfo[block].free.size;
  11724. X          if (_heaplimit != 0 && block + lastblocks == _heaplimit &&
  11725. X          (*__morecore) (0) == ADDRESS (block + lastblocks) &&
  11726. X          (morecore ((blocks - lastblocks) * BLOCKSIZE)) != NULL)
  11727. X        {
  11728. X          _heapinfo[block].free.size = blocks;
  11729. X          _bytes_free += (blocks - lastblocks) * BLOCKSIZE;
  11730. X          continue;
  11731. X        }
  11732. X          result = morecore (blocks * BLOCKSIZE);
  11733. X          if (result == NULL)
  11734. X        return NULL;
  11735. X          block = BLOCK (result);
  11736. X          _heapinfo[block].busy.type = 0;
  11737. X          _heapinfo[block].busy.info.size = blocks;
  11738. X          ++_chunks_used;
  11739. X          _bytes_used += blocks * BLOCKSIZE;
  11740. X          return result;
  11741. X        }
  11742. X    }
  11743. X
  11744. X      /* At this point we have found a suitable free list entry.
  11745. X     Figure out how to remove what we need from the list. */
  11746. X      result = ADDRESS (block);
  11747. X      if (_heapinfo[block].free.size > blocks)
  11748. X    {
  11749. X      /* The block we found has a bit left over,
  11750. X         so relink the tail end back into the free list. */
  11751. X      _heapinfo[block + blocks].free.size
  11752. X        = _heapinfo[block].free.size - blocks;
  11753. X      _heapinfo[block + blocks].free.next
  11754. X        = _heapinfo[block].free.next;
  11755. X      _heapinfo[block + blocks].free.prev
  11756. X        = _heapinfo[block].free.prev;
  11757. X      _heapinfo[_heapinfo[block].free.prev].free.next
  11758. X        = _heapinfo[_heapinfo[block].free.next].free.prev
  11759. X        = _heapindex = block + blocks;
  11760. X    }
  11761. X      else
  11762. X    {
  11763. X      /* The block exactly matches our requirements,
  11764. X         so just remove it from the list. */
  11765. X      _heapinfo[_heapinfo[block].free.next].free.prev
  11766. X        = _heapinfo[block].free.prev;
  11767. X      _heapinfo[_heapinfo[block].free.prev].free.next
  11768. X        = _heapindex = _heapinfo[block].free.next;
  11769. X      --_chunks_free;
  11770. X    }
  11771. X
  11772. X      _heapinfo[block].busy.type = 0;
  11773. X      _heapinfo[block].busy.info.size = blocks;
  11774. X      ++_chunks_used;
  11775. X      _bytes_used += blocks * BLOCKSIZE;
  11776. X      _bytes_free -= blocks * BLOCKSIZE;
  11777. X    }
  11778. X
  11779. X  return result;
  11780. X}
  11781. X/* Free a block of memory allocated by `malloc'.
  11782. X   Copyright 1990, 1991, 1992 Free Software Foundation
  11783. X          Written May 1989 by Mike Haertel.
  11784. X
  11785. XThis library is free software; you can redistribute it and/or
  11786. Xmodify it under the terms of the GNU Library General Public License as
  11787. Xpublished by the Free Software Foundation; either version 2 of the
  11788. XLicense, or (at your option) any later version.
  11789. X
  11790. XThis library is distributed in the hope that it will be useful,
  11791. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  11792. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  11793. XLibrary General Public License for more details.
  11794. X
  11795. XYou should have received a copy of the GNU Library General Public
  11796. XLicense along with this library; see the file COPYING.LIB.  If
  11797. Xnot, write to the Free Software Foundation, Inc., 675 Mass Ave,
  11798. XCambridge, MA 02139, USA.
  11799. X
  11800. X   The author may be reached (Email) at the address mike@ai.mit.edu,
  11801. X   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
  11802. X
  11803. X#ifndef    _MALLOC_INTERNAL
  11804. X#define _MALLOC_INTERNAL
  11805. X#include <malloc.h>
  11806. X#endif
  11807. X
  11808. X/* Debugging hook for free.  */
  11809. Xvoid (*__free_hook) __P ((__ptr_t __ptr));
  11810. X
  11811. X/* List of blocks allocated by memalign.  */
  11812. Xstruct alignlist *_aligned_blocks = NULL;
  11813. X
  11814. X/* Return memory to the heap.
  11815. X   Like `free' but don't call a __free_hook if there is one.  */
  11816. Xvoid
  11817. X_free_internal (ptr)
  11818. X     __ptr_t ptr;
  11819. X{
  11820. X  int type;
  11821. X  size_t block, blocks;
  11822. X  register size_t i;
  11823. X  struct list *prev, *next;
  11824. X
  11825. X  block = BLOCK (ptr);
  11826. X
  11827. X  type = _heapinfo[block].busy.type;
  11828. X  switch (type)
  11829. X    {
  11830. X    case 0:
  11831. X      /* Get as many statistics as early as we can.  */
  11832. X      --_chunks_used;
  11833. X      _bytes_used -= _heapinfo[block].busy.info.size * BLOCKSIZE;
  11834. X      _bytes_free += _heapinfo[block].busy.info.size * BLOCKSIZE;
  11835. X
  11836. X      /* Find the free cluster previous to this one in the free list.
  11837. X     Start searching at the last block referenced; this may benefit
  11838. X     programs with locality of allocation.  */
  11839. X      i = _heapindex;
  11840. X      if (i > block)
  11841. X    while (i > block)
  11842. X      i = _heapinfo[i].free.prev;
  11843. X      else
  11844. X    {
  11845. X      do
  11846. X        i = _heapinfo[i].free.next;
  11847. X      while (i > 0 && i < block);
  11848. X      i = _heapinfo[i].free.prev;
  11849. X    }
  11850. X
  11851. X      /* Determine how to link this block into the free list.  */
  11852. X      if (block == i + _heapinfo[i].free.size)
  11853. X    {
  11854. X      /* Coalesce this block with its predecessor.  */
  11855. X      _heapinfo[i].free.size += _heapinfo[block].busy.info.size;
  11856. X      block = i;
  11857. X    }
  11858. X      else
  11859. X    {
  11860. X      /* Really link this block back into the free list.  */
  11861. X      _heapinfo[block].free.size = _heapinfo[block].busy.info.size;
  11862. X      _heapinfo[block].free.next = _heapinfo[i].free.next;
  11863. X      _heapinfo[block].free.prev = i;
  11864. X      _heapinfo[i].free.next = block;
  11865. X      _heapinfo[_heapinfo[block].free.next].free.prev = block;
  11866. X      ++_chunks_free;
  11867. X    }
  11868. X
  11869. X      /* Now that the block is linked in, see if we can coalesce it
  11870. X     with its successor (by deleting its successor from the list
  11871. X     and adding in its size).  */
  11872. X      if (block + _heapinfo[block].free.size == _heapinfo[block].free.next)
  11873. X    {
  11874. X      _heapinfo[block].free.size
  11875. X        += _heapinfo[_heapinfo[block].free.next].free.size;
  11876. X      _heapinfo[block].free.next
  11877. X        = _heapinfo[_heapinfo[block].free.next].free.next;
  11878. X      _heapinfo[_heapinfo[block].free.next].free.prev = block;
  11879. X      --_chunks_free;
  11880. X    }
  11881. X
  11882. X      /* Now see if we can return stuff to the system.  */
  11883. X      blocks = _heapinfo[block].free.size;
  11884. X      if (blocks >= FINAL_FREE_BLOCKS && block + blocks == _heaplimit
  11885. X      && (*__morecore) (0) == ADDRESS (block + blocks))
  11886. X    {
  11887. X      register size_t bytes = blocks * BLOCKSIZE;
  11888. X      _heaplimit -= blocks;
  11889. X      (*__morecore) (-bytes);
  11890. X      _heapinfo[_heapinfo[block].free.prev].free.next
  11891. X        = _heapinfo[block].free.next;
  11892. X      _heapinfo[_heapinfo[block].free.next].free.prev
  11893. X        = _heapinfo[block].free.prev;
  11894. X      block = _heapinfo[block].free.prev;
  11895. X      --_chunks_free;
  11896. X      _bytes_free -= bytes;
  11897. X    }
  11898. X
  11899. X      /* Set the next search to begin at this block.  */
  11900. X      _heapindex = block;
  11901. X      break;
  11902. X
  11903. X    default:
  11904. X      /* Do some of the statistics.  */
  11905. X      --_chunks_used;
  11906. X      _bytes_used -= 1 << type;
  11907. X      ++_chunks_free;
  11908. X      _bytes_free += 1 << type;
  11909. X
  11910. X      /* Get the address of the first free fragment in this block.  */
  11911. X      prev = (struct list *) ((char *) ADDRESS (block) +
  11912. X               (_heapinfo[block].busy.info.frag.first << type));
  11913. X
  11914. X      if (_heapinfo[block].busy.info.frag.nfree == (BLOCKSIZE >> type) - 1)
  11915. X    {
  11916. X      /* If all fragments of this block are free, remove them
  11917. X         from the fragment list and free the whole block.  */
  11918. X      next = prev;
  11919. X      for (i = 1; i < (size_t) (BLOCKSIZE >> type); ++i)
  11920. X        next = next->next;
  11921. X      prev->prev->next = next;
  11922. X      if (next != NULL)
  11923. X        next->prev = prev->prev;
  11924. X      _heapinfo[block].busy.type = 0;
  11925. X      _heapinfo[block].busy.info.size = 1;
  11926. X
  11927. X      /* Keep the statistics accurate.  */
  11928. X      ++_chunks_used;
  11929. X      _bytes_used += BLOCKSIZE;
  11930. X      _chunks_free -= BLOCKSIZE >> type;
  11931. X      _bytes_free -= BLOCKSIZE;
  11932. X
  11933. X      free (ADDRESS (block));
  11934. X    }
  11935. X      else if (_heapinfo[block].busy.info.frag.nfree != 0)
  11936. X    {
  11937. X      /* If some fragments of this block are free, link this
  11938. X         fragment into the fragment list after the first free
  11939. X         fragment of this block. */
  11940. X      next = (struct list *) ptr;
  11941. X      next->next = prev->next;
  11942. X      next->prev = prev;
  11943. X      prev->next = next;
  11944. X      if (next->next != NULL)
  11945. X        next->next->prev = next;
  11946. X      ++_heapinfo[block].busy.info.frag.nfree;
  11947. X    }
  11948. X      else
  11949. X    {
  11950. X      /* No fragments of this block are free, so link this
  11951. X         fragment into the fragment list and announce that
  11952. X         it is the first free fragment of this block. */
  11953. X      prev = (struct list *) ptr;
  11954. X      _heapinfo[block].busy.info.frag.nfree = 1;
  11955. X      _heapinfo[block].busy.info.frag.first = (unsigned long int)
  11956. X        ((unsigned long int) ((char *) ptr - (char *) NULL)
  11957. X         % BLOCKSIZE >> type);
  11958. X      prev->next = _fraghead[type].next;
  11959. X      prev->prev = &_fraghead[type];
  11960. X      prev->prev->next = prev;
  11961. X      if (prev->next != NULL)
  11962. X        prev->next->prev = prev;
  11963. X    }
  11964. X      break;
  11965. X    }
  11966. X}
  11967. X
  11968. X/* Return memory to the heap.  */
  11969. Xvoid
  11970. Xfree (ptr)
  11971. X     __ptr_t ptr;
  11972. X{
  11973. X  register struct alignlist *l;
  11974. X
  11975. X  if (ptr == NULL)
  11976. X    return;
  11977. X
  11978. X  for (l = _aligned_blocks; l != NULL; l = l->next)
  11979. X    if (l->aligned == ptr)
  11980. X      {
  11981. X    l->aligned = NULL;    /* Mark the slot in the list as free.  */
  11982. X    ptr = l->exact;
  11983. X    break;
  11984. X      }
  11985. X
  11986. X  if (__free_hook != NULL)
  11987. X    (*__free_hook) (ptr);
  11988. X  else
  11989. X    _free_internal (ptr);
  11990. X}
  11991. X/* Change the size of a block allocated by `malloc'.
  11992. X   Copyright 1990, 1991, 1992 Free Software Foundation, Inc.
  11993. X             Written May 1989 by Mike Haertel.
  11994. X
  11995. XThis library is free software; you can redistribute it and/or
  11996. Xmodify it under the terms of the GNU Library General Public License as
  11997. Xpublished by the Free Software Foundation; either version 2 of the
  11998. XLicense, or (at your option) any later version.
  11999. X
  12000. XThis library is distributed in the hope that it will be useful,
  12001. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  12002. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12003. XLibrary General Public License for more details.
  12004. X
  12005. XYou should have received a copy of the GNU Library General Public
  12006. XLicense along with this library; see the file COPYING.LIB.  If
  12007. Xnot, write to the Free Software Foundation, Inc., 675 Mass Ave,
  12008. XCambridge, MA 02139, USA.
  12009. X
  12010. X   The author may be reached (Email) at the address mike@ai.mit.edu,
  12011. X   or (US mail) as Mike Haertel c/o Free Software Foundation.  */
  12012. X
  12013. X#ifndef    _MALLOC_INTERNAL
  12014. X#define _MALLOC_INTERNAL
  12015. X#include <malloc.h>
  12016. X#endif
  12017. X
  12018. X#define min(A, B) ((A) < (B) ? (A) : (B))
  12019. X
  12020. X/* Debugging hook for realloc.  */
  12021. X__ptr_t (*__realloc_hook) __P ((__ptr_t __ptr, size_t __size));
  12022. X
  12023. X/* Resize the given region to the new size, returning a pointer
  12024. X   to the (possibly moved) region.  This is optimized for speed;
  12025. X   some benchmarks seem to indicate that greater compactness is
  12026. X   achieved by unconditionally allocating and copying to a
  12027. X   new region.  This module has incestuous knowledge of the
  12028. X   internals of both free and malloc. */
  12029. X__ptr_t
  12030. Xrealloc (ptr, size)
  12031. X     __ptr_t ptr;
  12032. X     size_t size;
  12033. X{
  12034. X  __ptr_t result;
  12035. X  int type;
  12036. X  size_t block, blocks, oldlimit;
  12037. X
  12038. X  if (size == 0)
  12039. X    {
  12040. X      free (ptr);
  12041. X      return malloc (0);
  12042. X    }
  12043. X  else if (ptr == NULL)
  12044. X    return malloc (size);
  12045. X
  12046. X  if (__realloc_hook != NULL)
  12047. X    return (*__realloc_hook) (ptr, size);
  12048. X
  12049. X  block = BLOCK (ptr);
  12050. X
  12051. X  type = _heapinfo[block].busy.type;
  12052. X  switch (type)
  12053. X    {
  12054. X    case 0:
  12055. X      /* Maybe reallocate a large block to a small fragment.  */
  12056. X      if (size <= BLOCKSIZE / 2)
  12057. X    {
  12058. X      result = malloc (size);
  12059. X      if (result != NULL)
  12060. X        {
  12061. X          memcpy (result, ptr, size);
  12062. X          free (ptr);
  12063. X          return result;
  12064. X        }
  12065. X    }
  12066. X
  12067. X      /* The new size is a large allocation as well;
  12068. X     see if we can hold it in place. */
  12069. X      blocks = BLOCKIFY (size);
  12070. X      if (blocks < _heapinfo[block].busy.info.size)
  12071. X    {
  12072. X      /* The new size is smaller; return
  12073. X         excess memory to the free list. */
  12074. X      _heapinfo[block + blocks].busy.type = 0;
  12075. X      _heapinfo[block + blocks].busy.info.size
  12076. X        = _heapinfo[block].busy.info.size - blocks;
  12077. X      _heapinfo[block].busy.info.size = blocks;
  12078. X      free (ADDRESS (block + blocks));
  12079. X      result = ptr;
  12080. X    }
  12081. X      else if (blocks == _heapinfo[block].busy.info.size)
  12082. X    /* No size change necessary.  */
  12083. X    result = ptr;
  12084. X      else
  12085. X    {
  12086. X      /* Won't fit, so allocate a new region that will.
  12087. X         Free the old region first in case there is sufficient
  12088. X         adjacent free space to grow without moving. */
  12089. X      blocks = _heapinfo[block].busy.info.size;
  12090. X      /* Prevent free from actually returning memory to the system.  */
  12091. X      oldlimit = _heaplimit;
  12092. X      _heaplimit = 0;
  12093. X      free (ptr);
  12094. X      _heaplimit = oldlimit;
  12095. X      result = malloc (size);
  12096. X      if (result == NULL)
  12097. X        {
  12098. X          (void) malloc (blocks * BLOCKSIZE);
  12099. X          return NULL;
  12100. X        }
  12101. X      if (ptr != result)
  12102. X        memmove (result, ptr, blocks * BLOCKSIZE);
  12103. X    }
  12104. X      break;
  12105. X
  12106. X    default:
  12107. X      /* Old size is a fragment; type is logarithm
  12108. X     to base two of the fragment size.  */
  12109. X      if (size > (size_t) (1 << (type - 1)) && size <= (size_t) (1 << type))
  12110. X    /* The new size is the same kind of fragment.  */
  12111. X    result = ptr;
  12112. X      else
  12113. X    {
  12114. X      /* The new size is different; allocate a new space,
  12115. X         and copy the lesser of the new size and the old. */
  12116. X      result = malloc (size);
  12117. X      if (result == NULL)
  12118. X        return NULL;
  12119. X      memcpy (result, ptr, min (size, (size_t) 1 << type));
  12120. X      free (ptr);
  12121. X    }
  12122. X      break;
  12123. X    }
  12124. X
  12125. X  return result;
  12126. X}
  12127. X/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  12128. XThis file is part of the GNU C Library.
  12129. X
  12130. XThe GNU C Library is free software; you can redistribute it and/or modify
  12131. Xit under the terms of the GNU General Public License as published by
  12132. Xthe Free Software Foundation; either version 2, or (at your option)
  12133. Xany later version.
  12134. X
  12135. XThe GNU C Library is distributed in the hope that it will be useful,
  12136. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  12137. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12138. XGNU General Public License for more details.
  12139. X
  12140. XYou should have received a copy of the GNU General Public License
  12141. Xalong with the GNU C Library; see the file COPYING.  If not, write to
  12142. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  12143. X
  12144. X#ifndef    _MALLOC_INTERNAL
  12145. X#define    _MALLOC_INTERNAL
  12146. X#include <malloc.h>
  12147. X#endif
  12148. X
  12149. X#ifndef    __GNU_LIBRARY__
  12150. X#define    __sbrk    sbrk
  12151. X#endif
  12152. X
  12153. Xextern __ptr_t __sbrk __P ((int increment));
  12154. X
  12155. X#ifndef NULL
  12156. X#define NULL 0
  12157. X#endif
  12158. X
  12159. X/* Allocate INCREMENT more bytes of data space,
  12160. X   and return the start of data space, or NULL on errors.
  12161. X   If INCREMENT is negative, shrink data space.  */
  12162. X__ptr_t
  12163. X__default_morecore (increment)
  12164. X     ptrdiff_t increment;
  12165. X{
  12166. X  __ptr_t result = __sbrk ((int) increment);
  12167. X  if (result == (__ptr_t) -1)
  12168. X    return NULL;
  12169. X  return result;
  12170. X}
  12171. X/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  12172. X
  12173. XThis library is free software; you can redistribute it and/or
  12174. Xmodify it under the terms of the GNU Library General Public License as
  12175. Xpublished by the Free Software Foundation; either version 2 of the
  12176. XLicense, or (at your option) any later version.
  12177. X
  12178. XThis library is distributed in the hope that it will be useful,
  12179. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  12180. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12181. XLibrary General Public License for more details.
  12182. X
  12183. XYou should have received a copy of the GNU Library General Public
  12184. XLicense along with this library; see the file COPYING.LIB.  If
  12185. Xnot, write to the Free Software Foundation, Inc., 675 Mass Ave,
  12186. XCambridge, MA 02139, USA.  */
  12187. X
  12188. X#ifndef    _MALLOC_INTERNAL
  12189. X#define _MALLOC_INTERNAL
  12190. X#include <malloc.h>
  12191. X#endif
  12192. X
  12193. X__ptr_t
  12194. Xmemalign (alignment, size)
  12195. X     size_t alignment;
  12196. X     size_t size;
  12197. X{
  12198. X  __ptr_t result;
  12199. X  unsigned long int adj;
  12200. X
  12201. X  size = ((size + alignment - 1) / alignment) * alignment;
  12202. X
  12203. X  result = malloc (size);
  12204. X  if (result == NULL)
  12205. X    return NULL;
  12206. X  adj = (unsigned long int) ((unsigned long int) ((char *) result -
  12207. X                        (char *) NULL)) % alignment;
  12208. X  if (adj != 0)
  12209. X    {
  12210. X      struct alignlist *l;
  12211. X      for (l = _aligned_blocks; l != NULL; l = l->next)
  12212. X    if (l->aligned == NULL)
  12213. X      /* This slot is free.  Use it.  */
  12214. X      break;
  12215. X      if (l == NULL)
  12216. X    {
  12217. X      l = (struct alignlist *) malloc (sizeof (struct alignlist));
  12218. X      if (l == NULL)
  12219. X        {
  12220. X          free (result);
  12221. X          return NULL;
  12222. X        }
  12223. X    }
  12224. X      l->exact = result;
  12225. X      result = l->aligned = (char *) result + alignment - adj;
  12226. X      l->next = _aligned_blocks;
  12227. X      _aligned_blocks = l;
  12228. X    }
  12229. X
  12230. X  return result;
  12231. X}
  12232. END_OF_FILE
  12233. if test 30710 -ne `wc -c <'malloc.c'`; then
  12234.     echo shar: \"'malloc.c'\" unpacked with wrong size!
  12235. fi
  12236. # end of 'malloc.c'
  12237. fi
  12238. if test -f 'getopt1.c' -a "${1}" != "-c" ; then 
  12239.   echo shar: Will not clobber existing file \"'getopt1.c'\"
  12240. else
  12241. echo shar: Extracting \"'getopt1.c'\" \(3486 characters\)
  12242. sed "s/^X//" >'getopt1.c' <<'END_OF_FILE'
  12243. X/* Getopt for GNU.
  12244. X   Copyright (C) 1987, 88, 89, 90, 91, 1992 Free Software Foundation, Inc.
  12245. X
  12246. X   This program is free software; you can redistribute it and/or modify it
  12247. X   under the terms of the GNU General Public License as published by the
  12248. X   Free Software Foundation; either version 2, or (at your option) any
  12249. X   later version.
  12250. X   
  12251. X   This program is distributed in the hope that it will be useful,
  12252. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12253. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12254. X   GNU General Public License for more details.
  12255. X   
  12256. X   You should have received a copy of the GNU General Public License
  12257. X   along with this program; if not, write to the Free Software
  12258. X   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  12259. X
  12260. X#ifdef HAVE_CONFIG_H
  12261. X#include "config.h"
  12262. X#endif
  12263. X
  12264. X#include "getopt.h"
  12265. X
  12266. X#if !__STDC__ && !defined(const) && IN_GCC
  12267. X#define const
  12268. X#endif
  12269. X
  12270. X#include <stdio.h>
  12271. X
  12272. X/* This needs to come after some library #include
  12273. X   to get __GNU_LIBRARY__ defined.  */
  12274. X#ifdef __GNU_LIBRARY__
  12275. X#include <stdlib.h>
  12276. X#else
  12277. Xchar *getenv ();
  12278. X#endif
  12279. X
  12280. X#ifndef    NULL
  12281. X#define NULL 0
  12282. X#endif
  12283. X
  12284. Xint
  12285. Xgetopt_long (argc, argv, options, long_options, opt_index)
  12286. X     int argc;
  12287. X     char *const *argv;
  12288. X     const char *options;
  12289. X     const struct option *long_options;
  12290. X     int *opt_index;
  12291. X{
  12292. X  return _getopt_internal (argc, argv, options, long_options, opt_index, 0);
  12293. X}
  12294. X
  12295. X/* Like getopt_long, but '-' as well as '--' can indicate a long option.
  12296. X   If an option that starts with '-' (not '--') doesn't match a long option,
  12297. X   but does match a short option, it is parsed as a short option
  12298. X   instead.  */
  12299. X
  12300. Xint 
  12301. Xgetopt_long_only (argc, argv, options, long_options, opt_index)
  12302. X     int argc;
  12303. X     char *const *argv;
  12304. X     const char *options;
  12305. X     const struct option *long_options;
  12306. X     int *opt_index;
  12307. X{
  12308. X  return _getopt_internal (argc, argv, options, long_options, opt_index, 1);
  12309. X}
  12310. X
  12311. X#ifdef TEST
  12312. X
  12313. X#include <stdio.h>
  12314. X
  12315. Xint
  12316. Xmain (argc, argv)
  12317. X     int argc;
  12318. X     char **argv;
  12319. X{
  12320. X  int c;
  12321. X  int digit_optind = 0;
  12322. X
  12323. X  while (1)
  12324. X    {
  12325. X      int this_option_optind = optind ? optind : 1;
  12326. X      int option_index = 0;
  12327. X      static struct option long_options[] =
  12328. X      {
  12329. X    {"add", 1, 0, 0},
  12330. X    {"append", 0, 0, 0},
  12331. X    {"delete", 1, 0, 0},
  12332. X    {"verbose", 0, 0, 0},
  12333. X    {"create", 0, 0, 0},
  12334. X    {"file", 1, 0, 0},
  12335. X    {0, 0, 0, 0}
  12336. X      };
  12337. X
  12338. X      c = getopt_long (argc, argv, "abc:d:0123456789",
  12339. X               long_options, &option_index);
  12340. X      if (c == EOF)
  12341. X    break;
  12342. X
  12343. X      switch (c)
  12344. X    {
  12345. X    case 0:
  12346. X      printf ("option %s", long_options[option_index].name);
  12347. X      if (optarg)
  12348. X        printf (" with arg %s", optarg);
  12349. X      printf ("\n");
  12350. X      break;
  12351. X
  12352. X    case '0':
  12353. X    case '1':
  12354. X    case '2':
  12355. X    case '3':
  12356. X    case '4':
  12357. X    case '5':
  12358. X    case '6':
  12359. X    case '7':
  12360. X    case '8':
  12361. X    case '9':
  12362. X      if (digit_optind != 0 && digit_optind != this_option_optind)
  12363. X        printf ("digits occur in two different argv-elements.\n");
  12364. X      digit_optind = this_option_optind;
  12365. X      printf ("option %c\n", c);
  12366. X      break;
  12367. X
  12368. X    case 'a':
  12369. X      printf ("option a\n");
  12370. X      break;
  12371. X
  12372. X    case 'b':
  12373. X      printf ("option b\n");
  12374. X      break;
  12375. X
  12376. X    case 'c':
  12377. X      printf ("option c with value `%s'\n", optarg);
  12378. X      break;
  12379. X
  12380. X    case 'd':
  12381. X      printf ("option d with value `%s'\n", optarg);
  12382. X      break;
  12383. X
  12384. X    case '?':
  12385. X      break;
  12386. X
  12387. X    default:
  12388. X      printf ("?? getopt returned character code 0%o ??\n", c);
  12389. X    }
  12390. X    }
  12391. X
  12392. X  if (optind < argc)
  12393. X    {
  12394. X      printf ("non-option ARGV-elements: ");
  12395. X      while (optind < argc)
  12396. X    printf ("%s ", argv[optind++]);
  12397. X      printf ("\n");
  12398. X    }
  12399. X
  12400. X  exit (0);
  12401. X}
  12402. X
  12403. X#endif /* TEST */
  12404. END_OF_FILE
  12405. if test 3486 -ne `wc -c <'getopt1.c'`; then
  12406.     echo shar: \"'getopt1.c'\" unpacked with wrong size!
  12407. fi
  12408. # end of 'getopt1.c'
  12409. fi
  12410. if test -f 'regex.c' -a "${1}" != "-c" ; then 
  12411.   echo shar: Will not clobber existing file \"'regex.c'\"
  12412. else
  12413. echo shar: Extracting \"'regex.c'\" \(161195 characters\)
  12414. sed "s/^X//" >'regex.c' <<'END_OF_FILE'
  12415. X/* Extended regular expression matching and search library,
  12416. X   version 0.11.
  12417. X   (Implements POSIX draft P10003.2/D11.2, except for
  12418. X   internationalization features.)
  12419. X
  12420. X   Copyright (C) 1993 Free Software Foundation, Inc.
  12421. X
  12422. X   This program is free software; you can redistribute it and/or modify
  12423. X   it under the terms of the GNU General Public License as published by
  12424. X   the Free Software Foundation; either version 2, or (at your option)
  12425. X   any later version.
  12426. X
  12427. X   This program is distributed in the hope that it will be useful,
  12428. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  12429. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12430. X   GNU General Public License for more details.
  12431. X
  12432. X   You should have received a copy of the GNU General Public License
  12433. X   along with this program; if not, write to the Free Software
  12434. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  12435. X
  12436. X/* AIX requires this to be the first thing in the file. */
  12437. X#if defined (_AIX) && !defined (REGEX_MALLOC)
  12438. X  #pragma alloca
  12439. X#endif
  12440. X
  12441. X#define _GNU_SOURCE
  12442. X
  12443. X/* We need this for `regex.h', and perhaps for the Emacs include files.  */
  12444. X#include <sys/types.h>
  12445. X
  12446. X#ifdef HAVE_CONFIG_H
  12447. X#include "config.h"
  12448. X#endif
  12449. X
  12450. X/* The `emacs' switch turns on certain matching commands
  12451. X   that make sense only in Emacs. */
  12452. X#ifdef emacs
  12453. X
  12454. X#include "lisp.h"
  12455. X#include "buffer.h"
  12456. X#include "syntax.h"
  12457. X
  12458. X/* Emacs uses `NULL' as a predicate.  */
  12459. X#undef NULL
  12460. X
  12461. X#else  /* not emacs */
  12462. X
  12463. X/* We used to test for `BSTRING' here, but only GCC and Emacs define
  12464. X   `BSTRING', as far as I know, and neither of them use this code.  */
  12465. X#if HAVE_STRING_H || STDC_HEADERS
  12466. X#include <string.h>
  12467. X#ifndef bcmp
  12468. X#define bcmp(s1, s2, n)    memcmp ((s1), (s2), (n))
  12469. X#endif
  12470. X#ifndef bcopy
  12471. X#define bcopy(s, d, n)    memcpy ((d), (s), (n))
  12472. X#endif
  12473. X#ifndef bzero
  12474. X#define bzero(s, n)    memset ((s), 0, (n))
  12475. X#endif
  12476. X#else
  12477. X#include <strings.h>
  12478. X#endif
  12479. X
  12480. X#ifdef STDC_HEADERS
  12481. X#include <stdlib.h>
  12482. X#else
  12483. Xchar *malloc ();
  12484. Xchar *realloc ();
  12485. X#endif
  12486. X
  12487. X
  12488. X/* Define the syntax stuff for \<, \>, etc.  */
  12489. X
  12490. X/* This must be nonzero for the wordchar and notwordchar pattern
  12491. X   commands in re_match_2.  */
  12492. X#ifndef Sword 
  12493. X#define Sword 1
  12494. X#endif
  12495. X
  12496. X#ifdef SYNTAX_TABLE
  12497. X
  12498. Xextern char *re_syntax_table;
  12499. X
  12500. X#else /* not SYNTAX_TABLE */
  12501. X
  12502. X/* How many characters in the character set.  */
  12503. X#define CHAR_SET_SIZE 256
  12504. X
  12505. Xstatic char re_syntax_table[CHAR_SET_SIZE];
  12506. X
  12507. Xstatic void
  12508. Xinit_syntax_once ()
  12509. X{
  12510. X   register int c;
  12511. X   static int done = 0;
  12512. X
  12513. X   if (done)
  12514. X     return;
  12515. X
  12516. X   bzero (re_syntax_table, sizeof re_syntax_table);
  12517. X
  12518. X   for (c = 'a'; c <= 'z'; c++)
  12519. X     re_syntax_table[c] = Sword;
  12520. X
  12521. X   for (c = 'A'; c <= 'Z'; c++)
  12522. X     re_syntax_table[c] = Sword;
  12523. X
  12524. X   for (c = '0'; c <= '9'; c++)
  12525. X     re_syntax_table[c] = Sword;
  12526. X
  12527. X   re_syntax_table['_'] = Sword;
  12528. X
  12529. X   done = 1;
  12530. X}
  12531. X
  12532. X#endif /* not SYNTAX_TABLE */
  12533. X
  12534. X#define SYNTAX(c) re_syntax_table[c]
  12535. X
  12536. X#endif /* not emacs */
  12537. X
  12538. X/* Get the interface, including the syntax bits.  */
  12539. X#include "regex.h"
  12540. X
  12541. X/* isalpha etc. are used for the character classes.  */
  12542. X#include <ctype.h>
  12543. X
  12544. X#ifndef isascii
  12545. X#define isascii(c) 1
  12546. X#endif
  12547. X
  12548. X#ifdef isblank
  12549. X#define ISBLANK(c) (isascii (c) && isblank (c))
  12550. X#else
  12551. X#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
  12552. X#endif
  12553. X#ifdef isgraph
  12554. X#define ISGRAPH(c) (isascii (c) && isgraph (c))
  12555. X#else
  12556. X#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c))
  12557. X#endif
  12558. X
  12559. X#define ISPRINT(c) (isascii (c) && isprint (c))
  12560. X#define ISDIGIT(c) (isascii (c) && isdigit (c))
  12561. X#define ISALNUM(c) (isascii (c) && isalnum (c))
  12562. X#define ISALPHA(c) (isascii (c) && isalpha (c))
  12563. X#define ISCNTRL(c) (isascii (c) && iscntrl (c))
  12564. X#define ISLOWER(c) (isascii (c) && islower (c))
  12565. X#define ISPUNCT(c) (isascii (c) && ispunct (c))
  12566. X#define ISSPACE(c) (isascii (c) && isspace (c))
  12567. X#define ISUPPER(c) (isascii (c) && isupper (c))
  12568. X#define ISXDIGIT(c) (isascii (c) && isxdigit (c))
  12569. X
  12570. X#ifndef NULL
  12571. X#define NULL 0
  12572. X#endif
  12573. X
  12574. X/* We remove any previous definition of `SIGN_EXTEND_CHAR',
  12575. X   since ours (we hope) works properly with all combinations of
  12576. X   machines, compilers, `char' and `unsigned char' argument types.
  12577. X   (Per Bothner suggested the basic approach.)  */
  12578. X#undef SIGN_EXTEND_CHAR
  12579. X#if __STDC__
  12580. X#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
  12581. X#else  /* not __STDC__ */
  12582. X/* As in Harbison and Steele.  */
  12583. X#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
  12584. X#endif
  12585. X
  12586. X/* Should we use malloc or alloca?  If REGEX_MALLOC is not defined, we
  12587. X   use `alloca' instead of `malloc'.  This is because using malloc in
  12588. X   re_search* or re_match* could cause memory leaks when C-g is used in
  12589. X   Emacs; also, malloc is slower and causes storage fragmentation.  On
  12590. X   the other hand, malloc is more portable, and easier to debug.  
  12591. X   
  12592. X   Because we sometimes use alloca, some routines have to be macros,
  12593. X   not functions -- `alloca'-allocated space disappears at the end of the
  12594. X   function it is called in.  */
  12595. X
  12596. X#ifdef REGEX_MALLOC
  12597. X
  12598. X#define REGEX_ALLOCATE malloc
  12599. X#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
  12600. X
  12601. X#else /* not REGEX_MALLOC  */
  12602. X
  12603. X/* Emacs already defines alloca, sometimes.  */
  12604. X#ifndef alloca
  12605. X
  12606. X/* Make alloca work the best possible way.  */
  12607. X#ifdef __GNUC__
  12608. X#define alloca __builtin_alloca
  12609. X#else /* not __GNUC__ */
  12610. X#if HAVE_ALLOCA_H
  12611. X#include <alloca.h>
  12612. X#else /* not __GNUC__ or HAVE_ALLOCA_H */
  12613. X#ifndef _AIX /* Already did AIX, up at the top.  */
  12614. Xchar *alloca ();
  12615. X#endif /* not _AIX */
  12616. X#endif /* not HAVE_ALLOCA_H */ 
  12617. X#endif /* not __GNUC__ */
  12618. X
  12619. X#endif /* not alloca */
  12620. X
  12621. X#define REGEX_ALLOCATE alloca
  12622. X
  12623. X/* Assumes a `char *destination' variable.  */
  12624. X#define REGEX_REALLOCATE(source, osize, nsize)                \
  12625. X  (destination = (char *) alloca (nsize),                \
  12626. X   bcopy (source, destination, osize),                    \
  12627. X   destination)
  12628. X
  12629. X#endif /* not REGEX_MALLOC */
  12630. X
  12631. X
  12632. X/* True if `size1' is non-NULL and PTR is pointing anywhere inside
  12633. X   `string1' or just past its end.  This works if PTR is NULL, which is
  12634. X   a good thing.  */
  12635. X#define FIRST_STRING_P(ptr)                     \
  12636. X  (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
  12637. X
  12638. X/* (Re)Allocate N items of type T using malloc, or fail.  */
  12639. X#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
  12640. X#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
  12641. X#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
  12642. X
  12643. X#define BYTEWIDTH 8 /* In bits.  */
  12644. X
  12645. X#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
  12646. X
  12647. X#define MAX(a, b) ((a) > (b) ? (a) : (b))
  12648. X#define MIN(a, b) ((a) < (b) ? (a) : (b))
  12649. X
  12650. Xtypedef char boolean;
  12651. X#define false 0
  12652. X#define true 1
  12653. X
  12654. X/* These are the command codes that appear in compiled regular
  12655. X   expressions.  Some opcodes are followed by argument bytes.  A
  12656. X   command code can specify any interpretation whatsoever for its
  12657. X   arguments.  Zero bytes may appear in the compiled regular expression.
  12658. X
  12659. X   The value of `exactn' is needed in search.c (search_buffer) in Emacs.
  12660. X   So regex.h defines a symbol `RE_EXACTN_VALUE' to be 1; the value of
  12661. X   `exactn' we use here must also be 1.  */
  12662. X
  12663. Xtypedef enum
  12664. X{
  12665. X  no_op = 0,
  12666. X
  12667. X        /* Followed by one byte giving n, then by n literal bytes.  */
  12668. X  exactn = 1,
  12669. X
  12670. X        /* Matches any (more or less) character.  */
  12671. X  anychar,
  12672. X
  12673. X        /* Matches any one char belonging to specified set.  First
  12674. X           following byte is number of bitmap bytes.  Then come bytes
  12675. X           for a bitmap saying which chars are in.  Bits in each byte
  12676. X           are ordered low-bit-first.  A character is in the set if its
  12677. X           bit is 1.  A character too large to have a bit in the map is
  12678. X           automatically not in the set.  */
  12679. X  charset,
  12680. X
  12681. X        /* Same parameters as charset, but match any character that is
  12682. X           not one of those specified.  */
  12683. X  charset_not,
  12684. X
  12685. X        /* Start remembering the text that is matched, for storing in a
  12686. X           register.  Followed by one byte with the register number, in
  12687. X           the range 0 to one less than the pattern buffer's re_nsub
  12688. X           field.  Then followed by one byte with the number of groups
  12689. X           inner to this one.  (This last has to be part of the
  12690. X           start_memory only because we need it in the on_failure_jump
  12691. X           of re_match_2.)  */
  12692. X  start_memory,
  12693. X
  12694. X        /* Stop remembering the text that is matched and store it in a
  12695. X           memory register.  Followed by one byte with the register
  12696. X           number, in the range 0 to one less than `re_nsub' in the
  12697. X           pattern buffer, and one byte with the number of inner groups,
  12698. X           just like `start_memory'.  (We need the number of inner
  12699. X           groups here because we don't have any easy way of finding the
  12700. X           corresponding start_memory when we're at a stop_memory.)  */
  12701. X  stop_memory,
  12702. X
  12703. X        /* Match a duplicate of something remembered. Followed by one
  12704. X           byte containing the register number.  */
  12705. X  duplicate,
  12706. X
  12707. X        /* Fail unless at beginning of line.  */
  12708. X  begline,
  12709. X
  12710. X        /* Fail unless at end of line.  */
  12711. X  endline,
  12712. X
  12713. X        /* Succeeds if at beginning of buffer (if emacs) or at beginning
  12714. X           of string to be matched (if not).  */
  12715. X  begbuf,
  12716. X
  12717. X        /* Analogously, for end of buffer/string.  */
  12718. X  endbuf,
  12719. X        /* Followed by two byte relative address to which to jump.  */
  12720. X  jump, 
  12721. X
  12722. X    /* Same as jump, but marks the end of an alternative.  */
  12723. X  jump_past_alt,
  12724. X
  12725. X        /* Followed by two-byte relative address of place to resume at
  12726. X           in case of failure.  */
  12727. X  on_failure_jump,
  12728. X    
  12729. X        /* Like on_failure_jump, but pushes a placeholder instead of the
  12730. X           current string position when executed.  */
  12731. X  on_failure_keep_string_jump,
  12732. X  
  12733. X        /* Throw away latest failure point and then jump to following
  12734. X           two-byte relative address.  */
  12735. X  pop_failure_jump,
  12736. X
  12737. X        /* Change to pop_failure_jump if know won't have to backtrack to
  12738. X           match; otherwise change to jump.  This is used to jump
  12739. X           back to the beginning of a repeat.  If what follows this jump
  12740. X           clearly won't match what the repeat does, such that we can be
  12741. X           sure that there is no use backtracking out of repetitions
  12742. X           already matched, then we change it to a pop_failure_jump.
  12743. X           Followed by two-byte address.  */
  12744. X  maybe_pop_jump,
  12745. X
  12746. X        /* Jump to following two-byte address, and push a dummy failure
  12747. X           point. This failure point will be thrown away if an attempt
  12748. X           is made to use it for a failure.  A `+' construct makes this
  12749. X           before the first repeat.  Also used as an intermediary kind
  12750. X           of jump when compiling an alternative.  */
  12751. X  dummy_failure_jump,
  12752. X
  12753. X    /* Push a dummy failure point and continue.  Used at the end of
  12754. X       alternatives.  */
  12755. X  push_dummy_failure,
  12756. X
  12757. X        /* Followed by two-byte relative address and two-byte number n.
  12758. X           After matching N times, jump to the address upon failure.  */
  12759. X  succeed_n,
  12760. X
  12761. X        /* Followed by two-byte relative address, and two-byte number n.
  12762. X           Jump to the address N times, then fail.  */
  12763. X  jump_n,
  12764. X
  12765. X        /* Set the following two-byte relative address to the
  12766. X           subsequent two-byte number.  The address *includes* the two
  12767. X           bytes of number.  */
  12768. X  set_number_at,
  12769. X
  12770. X  wordchar,    /* Matches any word-constituent character.  */
  12771. X  notwordchar,    /* Matches any char that is not a word-constituent.  */
  12772. X
  12773. X  wordbeg,    /* Succeeds if at word beginning.  */
  12774. X  wordend,    /* Succeeds if at word end.  */
  12775. X
  12776. X  wordbound,    /* Succeeds if at a word boundary.  */
  12777. X  notwordbound    /* Succeeds if not at a word boundary.  */
  12778. X
  12779. X#ifdef emacs
  12780. X  ,before_dot,    /* Succeeds if before point.  */
  12781. X  at_dot,    /* Succeeds if at point.  */
  12782. X  after_dot,    /* Succeeds if after point.  */
  12783. X
  12784. X    /* Matches any character whose syntax is specified.  Followed by
  12785. X           a byte which contains a syntax code, e.g., Sword.  */
  12786. X  syntaxspec,
  12787. X
  12788. X    /* Matches any character whose syntax is not that specified.  */
  12789. X  notsyntaxspec
  12790. X#endif /* emacs */
  12791. X} re_opcode_t;
  12792. X
  12793. X/* Common operations on the compiled pattern.  */
  12794. X
  12795. X/* Store NUMBER in two contiguous bytes starting at DESTINATION.  */
  12796. X
  12797. X#define STORE_NUMBER(destination, number)                \
  12798. X  do {                                    \
  12799. X    (destination)[0] = (number) & 0377;                    \
  12800. X    (destination)[1] = (number) >> 8;                    \
  12801. X  } while (0)
  12802. X
  12803. X/* Same as STORE_NUMBER, except increment DESTINATION to
  12804. X   the byte after where the number is stored.  Therefore, DESTINATION
  12805. X   must be an lvalue.  */
  12806. X
  12807. X#define STORE_NUMBER_AND_INCR(destination, number)            \
  12808. X  do {                                    \
  12809. X    STORE_NUMBER (destination, number);                    \
  12810. X    (destination) += 2;                            \
  12811. X  } while (0)
  12812. X
  12813. X/* Put into DESTINATION a number stored in two contiguous bytes starting
  12814. X   at SOURCE.  */
  12815. X
  12816. X#define EXTRACT_NUMBER(destination, source)                \
  12817. X  do {                                    \
  12818. X    (destination) = *(source) & 0377;                    \
  12819. X    (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8;        \
  12820. X  } while (0)
  12821. X
  12822. X#ifdef DEBUG
  12823. Xstatic void
  12824. Xextract_number (dest, source)
  12825. X    int *dest;
  12826. X    unsigned char *source;
  12827. X{
  12828. X  int temp = SIGN_EXTEND_CHAR (*(source + 1)); 
  12829. X  *dest = *source & 0377;
  12830. X  *dest += temp << 8;
  12831. X}
  12832. X
  12833. X#ifndef EXTRACT_MACROS /* To debug the macros.  */
  12834. X#undef EXTRACT_NUMBER
  12835. X#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
  12836. X#endif /* not EXTRACT_MACROS */
  12837. X
  12838. X#endif /* DEBUG */
  12839. X
  12840. X/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
  12841. X   SOURCE must be an lvalue.  */
  12842. X
  12843. X#define EXTRACT_NUMBER_AND_INCR(destination, source)            \
  12844. X  do {                                    \
  12845. X    EXTRACT_NUMBER (destination, source);                \
  12846. X    (source) += 2;                             \
  12847. X  } while (0)
  12848. X
  12849. X#ifdef DEBUG
  12850. Xstatic void
  12851. Xextract_number_and_incr (destination, source)
  12852. X    int *destination;
  12853. X    unsigned char **source;
  12854. X{ 
  12855. X  extract_number (destination, *source);
  12856. X  *source += 2;
  12857. X}
  12858. X
  12859. X#ifndef EXTRACT_MACROS
  12860. X#undef EXTRACT_NUMBER_AND_INCR
  12861. X#define EXTRACT_NUMBER_AND_INCR(dest, src) \
  12862. X  extract_number_and_incr (&dest, &src)
  12863. X#endif /* not EXTRACT_MACROS */
  12864. X
  12865. X#endif /* DEBUG */
  12866. X
  12867. X/* If DEBUG is defined, Regex prints many voluminous messages about what
  12868. X   it is doing (if the variable `debug' is nonzero).  If linked with the
  12869. X   main program in `iregex.c', you can enter patterns and strings
  12870. X   interactively.  And if linked with the main program in `main.c' and
  12871. X   the other test files, you can run the already-written tests.  */
  12872. X
  12873. X#ifdef DEBUG
  12874. X
  12875. X/* We use standard I/O for debugging.  */
  12876. X#include <stdio.h>
  12877. X
  12878. X/* It is useful to test things that ``must'' be true when debugging.  */
  12879. X#include <assert.h>
  12880. X
  12881. Xstatic int debug = 0;
  12882. X
  12883. X#define DEBUG_STATEMENT(e) e
  12884. X#define DEBUG_PRINT1(x) if (debug) printf (x)
  12885. X#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
  12886. X#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
  12887. X#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
  12888. X#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)                 \
  12889. X  if (debug) print_partial_compiled_pattern (s, e)
  12890. X#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)            \
  12891. X  if (debug) print_double_string (w, s1, sz1, s2, sz2)
  12892. X
  12893. X
  12894. Xextern void printchar ();
  12895. X
  12896. X/* Print the fastmap in human-readable form.  */
  12897. X
  12898. Xvoid
  12899. Xprint_fastmap (fastmap)
  12900. X    char *fastmap;
  12901. X{
  12902. X  unsigned was_a_range = 0;
  12903. X  unsigned i = 0;  
  12904. X  
  12905. X  while (i < (1 << BYTEWIDTH))
  12906. X    {
  12907. X      if (fastmap[i++])
  12908. X    {
  12909. X      was_a_range = 0;
  12910. X          printchar (i - 1);
  12911. X          while (i < (1 << BYTEWIDTH)  &&  fastmap[i])
  12912. X            {
  12913. X              was_a_range = 1;
  12914. X              i++;
  12915. X            }
  12916. X      if (was_a_range)
  12917. X            {
  12918. X              printf ("-");
  12919. X              printchar (i - 1);
  12920. X            }
  12921. X        }
  12922. X    }
  12923. X  putchar ('\n'); 
  12924. X}
  12925. X
  12926. X
  12927. X/* Print a compiled pattern string in human-readable form, starting at
  12928. X   the START pointer into it and ending just before the pointer END.  */
  12929. X
  12930. Xvoid
  12931. Xprint_partial_compiled_pattern (start, end)
  12932. X    unsigned char *start;
  12933. X    unsigned char *end;
  12934. X{
  12935. X  int mcnt, mcnt2;
  12936. X  unsigned char *p = start;
  12937. X  unsigned char *pend = end;
  12938. X
  12939. X  if (start == NULL)
  12940. X    {
  12941. X      printf ("(null)\n");
  12942. X      return;
  12943. X    }
  12944. X    
  12945. X  /* Loop over pattern commands.  */
  12946. X  while (p < pend)
  12947. X    {
  12948. X      switch ((re_opcode_t) *p++)
  12949. X    {
  12950. X        case no_op:
  12951. X          printf ("/no_op");
  12952. X          break;
  12953. X
  12954. X    case exactn:
  12955. X      mcnt = *p++;
  12956. X          printf ("/exactn/%d", mcnt);
  12957. X          do
  12958. X        {
  12959. X              putchar ('/');
  12960. X          printchar (*p++);
  12961. X            }
  12962. X          while (--mcnt);
  12963. X          break;
  12964. X
  12965. X    case start_memory:
  12966. X          mcnt = *p++;
  12967. X          printf ("/start_memory/%d/%d", mcnt, *p++);
  12968. X          break;
  12969. X
  12970. X    case stop_memory:
  12971. X          mcnt = *p++;
  12972. X      printf ("/stop_memory/%d/%d", mcnt, *p++);
  12973. X          break;
  12974. X
  12975. X    case duplicate:
  12976. X      printf ("/duplicate/%d", *p++);
  12977. X      break;
  12978. X
  12979. X    case anychar:
  12980. X      printf ("/anychar");
  12981. X      break;
  12982. X
  12983. X    case charset:
  12984. X        case charset_not:
  12985. X          {
  12986. X            register int c;
  12987. X
  12988. X            printf ("/charset%s",
  12989. X                (re_opcode_t) *(p - 1) == charset_not ? "_not" : "");
  12990. X            
  12991. X            assert (p + *p < pend);
  12992. X
  12993. X            for (c = 0; c < *p; c++)
  12994. X              {
  12995. X                unsigned bit;
  12996. X                unsigned char map_byte = p[1 + c];
  12997. X                
  12998. X                putchar ('/');
  12999. X
  13000. X        for (bit = 0; bit < BYTEWIDTH; bit++)
  13001. X                  if (map_byte & (1 << bit))
  13002. X                    printchar (c * BYTEWIDTH + bit);
  13003. X              }
  13004. X        p += 1 + *p;
  13005. X        break;
  13006. X      }
  13007. X
  13008. X    case begline:
  13009. X      printf ("/begline");
  13010. X          break;
  13011. X
  13012. X    case endline:
  13013. X          printf ("/endline");
  13014. X          break;
  13015. X
  13016. X    case on_failure_jump:
  13017. X          extract_number_and_incr (&mcnt, &p);
  13018. X        printf ("/on_failure_jump/0/%d", mcnt);
  13019. X          break;
  13020. X
  13021. X    case on_failure_keep_string_jump:
  13022. X          extract_number_and_incr (&mcnt, &p);
  13023. X        printf ("/on_failure_keep_string_jump/0/%d", mcnt);
  13024. X          break;
  13025. X
  13026. X    case dummy_failure_jump:
  13027. X          extract_number_and_incr (&mcnt, &p);
  13028. X        printf ("/dummy_failure_jump/0/%d", mcnt);
  13029. X          break;
  13030. X
  13031. X    case push_dummy_failure:
  13032. X          printf ("/push_dummy_failure");
  13033. X          break;
  13034. X          
  13035. X        case maybe_pop_jump:
  13036. X          extract_number_and_incr (&mcnt, &p);
  13037. X        printf ("/maybe_pop_jump/0/%d", mcnt);
  13038. X      break;
  13039. X
  13040. X        case pop_failure_jump:
  13041. X      extract_number_and_incr (&mcnt, &p);
  13042. X        printf ("/pop_failure_jump/0/%d", mcnt);
  13043. X      break;          
  13044. X          
  13045. X        case jump_past_alt:
  13046. X      extract_number_and_incr (&mcnt, &p);
  13047. X        printf ("/jump_past_alt/0/%d", mcnt);
  13048. X      break;          
  13049. X          
  13050. X        case jump:
  13051. X      extract_number_and_incr (&mcnt, &p);
  13052. X        printf ("/jump/0/%d", mcnt);
  13053. X      break;
  13054. X
  13055. X        case succeed_n: 
  13056. X          extract_number_and_incr (&mcnt, &p);
  13057. X          extract_number_and_incr (&mcnt2, &p);
  13058. X       printf ("/succeed_n/0/%d/0/%d", mcnt, mcnt2);
  13059. X          break;
  13060. X        
  13061. X        case jump_n: 
  13062. X          extract_number_and_incr (&mcnt, &p);
  13063. X          extract_number_and_incr (&mcnt2, &p);
  13064. X       printf ("/jump_n/0/%d/0/%d", mcnt, mcnt2);
  13065. X          break;
  13066. X        
  13067. X        case set_number_at: 
  13068. X          extract_number_and_incr (&mcnt, &p);
  13069. X          extract_number_and_incr (&mcnt2, &p);
  13070. X       printf ("/set_number_at/0/%d/0/%d", mcnt, mcnt2);
  13071. X          break;
  13072. X        
  13073. X        case wordbound:
  13074. X      printf ("/wordbound");
  13075. X      break;
  13076. X
  13077. X    case notwordbound:
  13078. X      printf ("/notwordbound");
  13079. X          break;
  13080. X
  13081. X    case wordbeg:
  13082. X      printf ("/wordbeg");
  13083. X      break;
  13084. X          
  13085. X    case wordend:
  13086. X      printf ("/wordend");
  13087. X          
  13088. X#ifdef emacs
  13089. X    case before_dot:
  13090. X      printf ("/before_dot");
  13091. X          break;
  13092. X
  13093. X    case at_dot:
  13094. X      printf ("/at_dot");
  13095. X          break;
  13096. X
  13097. X    case after_dot:
  13098. X      printf ("/after_dot");
  13099. X          break;
  13100. X
  13101. X    case syntaxspec:
  13102. X          printf ("/syntaxspec");
  13103. X      mcnt = *p++;
  13104. X      printf ("/%d", mcnt);
  13105. X          break;
  13106. X      
  13107. X    case notsyntaxspec:
  13108. X          printf ("/notsyntaxspec");
  13109. X      mcnt = *p++;
  13110. X      printf ("/%d", mcnt);
  13111. X      break;
  13112. X#endif /* emacs */
  13113. X
  13114. X    case wordchar:
  13115. X      printf ("/wordchar");
  13116. X          break;
  13117. X      
  13118. X    case notwordchar:
  13119. X      printf ("/notwordchar");
  13120. X          break;
  13121. X
  13122. X    case begbuf:
  13123. X      printf ("/begbuf");
  13124. X          break;
  13125. X
  13126. X    case endbuf:
  13127. X      printf ("/endbuf");
  13128. X          break;
  13129. X
  13130. X        default:
  13131. X          printf ("?%d", *(p-1));
  13132. X    }
  13133. X    }
  13134. X  printf ("/\n");
  13135. X}
  13136. X
  13137. X
  13138. Xvoid
  13139. Xprint_compiled_pattern (bufp)
  13140. X    struct re_pattern_buffer *bufp;
  13141. X{
  13142. X  unsigned char *buffer = bufp->buffer;
  13143. X
  13144. X  print_partial_compiled_pattern (buffer, buffer + bufp->used);
  13145. X  printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
  13146. X
  13147. X  if (bufp->fastmap_accurate && bufp->fastmap)
  13148. X    {
  13149. X      printf ("fastmap: ");
  13150. X      print_fastmap (bufp->fastmap);
  13151. X    }
  13152. X
  13153. X  printf ("re_nsub: %d\t", bufp->re_nsub);
  13154. X  printf ("regs_alloc: %d\t", bufp->regs_allocated);
  13155. X  printf ("can_be_null: %d\t", bufp->can_be_null);
  13156. X  printf ("newline_anchor: %d\n", bufp->newline_anchor);
  13157. X  printf ("no_sub: %d\t", bufp->no_sub);
  13158. X  printf ("not_bol: %d\t", bufp->not_bol);
  13159. X  printf ("not_eol: %d\t", bufp->not_eol);
  13160. X  printf ("syntax: %d\n", bufp->syntax);
  13161. X  /* Perhaps we should print the translate table?  */
  13162. X}
  13163. X
  13164. X
  13165. Xvoid
  13166. Xprint_double_string (where, string1, size1, string2, size2)
  13167. X    const char *where;
  13168. X    const char *string1;
  13169. X    const char *string2;
  13170. X    int size1;
  13171. X    int size2;
  13172. X{
  13173. X  unsigned this_char;
  13174. X  
  13175. X  if (where == NULL)
  13176. X    printf ("(null)");
  13177. X  else
  13178. X    {
  13179. X      if (FIRST_STRING_P (where))
  13180. X        {
  13181. X          for (this_char = where - string1; this_char < size1; this_char++)
  13182. X            printchar (string1[this_char]);
  13183. X
  13184. X          where = string2;    
  13185. X        }
  13186. X
  13187. X      for (this_char = where - string2; this_char < size2; this_char++)
  13188. X        printchar (string2[this_char]);
  13189. X    }
  13190. X}
  13191. X
  13192. X#else /* not DEBUG */
  13193. X
  13194. X#undef assert
  13195. X#define assert(e)
  13196. X
  13197. X#define DEBUG_STATEMENT(e)
  13198. X#define DEBUG_PRINT1(x)
  13199. X#define DEBUG_PRINT2(x1, x2)
  13200. X#define DEBUG_PRINT3(x1, x2, x3)
  13201. X#define DEBUG_PRINT4(x1, x2, x3, x4)
  13202. X#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
  13203. X#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
  13204. X
  13205. X#endif /* not DEBUG */
  13206. X
  13207. X/* Set by `re_set_syntax' to the current regexp syntax to recognize.  Can
  13208. X   also be assigned to arbitrarily: each pattern buffer stores its own
  13209. X   syntax, so it can be changed between regex compilations.  */
  13210. Xreg_syntax_t re_syntax_options = RE_SYNTAX_EMACS;
  13211. X
  13212. X
  13213. X/* Specify the precise syntax of regexps for compilation.  This provides
  13214. X   for compatibility for various utilities which historically have
  13215. X   different, incompatible syntaxes.
  13216. X
  13217. X   The argument SYNTAX is a bit mask comprised of the various bits
  13218. X   defined in regex.h.  We return the old syntax.  */
  13219. X
  13220. Xreg_syntax_t
  13221. Xre_set_syntax (syntax)
  13222. X    reg_syntax_t syntax;
  13223. X{
  13224. X  reg_syntax_t ret = re_syntax_options;
  13225. X  
  13226. X  re_syntax_options = syntax;
  13227. X  return ret;
  13228. X}
  13229. X
  13230. X/* This table gives an error message for each of the error codes listed
  13231. X   in regex.h.  Obviously the order here has to be same as there.  */
  13232. X
  13233. Xstatic const char *re_error_msg[] =
  13234. X  { NULL,                    /* REG_NOERROR */
  13235. X    "No match",                    /* REG_NOMATCH */
  13236. X    "Invalid regular expression",        /* REG_BADPAT */
  13237. X    "Invalid collation character",        /* REG_ECOLLATE */
  13238. X    "Invalid character class name",        /* REG_ECTYPE */
  13239. X    "Trailing backslash",            /* REG_EESCAPE */
  13240. X    "Invalid back reference",            /* REG_ESUBREG */
  13241. X    "Unmatched [ or [^",            /* REG_EBRACK */
  13242. X    "Unmatched ( or \\(",            /* REG_EPAREN */
  13243. X    "Unmatched \\{",                /* REG_EBRACE */
  13244. X    "Invalid content of \\{\\}",        /* REG_BADBR */
  13245. X    "Invalid range end",            /* REG_ERANGE */
  13246. X    "Memory exhausted",                /* REG_ESPACE */
  13247. X    "Invalid preceding regular expression",    /* REG_BADRPT */
  13248. X    "Premature end of regular expression",    /* REG_EEND */
  13249. X    "Regular expression too big",        /* REG_ESIZE */
  13250. X    "Unmatched ) or \\)",            /* REG_ERPAREN */
  13251. X  };
  13252. X
  13253. X/* Subroutine declarations and macros for regex_compile.  */
  13254. X
  13255. Xstatic void store_op1 (), store_op2 ();
  13256. Xstatic void insert_op1 (), insert_op2 ();
  13257. Xstatic boolean at_begline_loc_p (), at_endline_loc_p ();
  13258. Xstatic boolean group_in_compile_stack ();
  13259. Xstatic reg_errcode_t compile_range ();
  13260. X
  13261. X/* Fetch the next character in the uncompiled pattern---translating it 
  13262. X   if necessary.  Also cast from a signed character in the constant
  13263. X   string passed to us by the user to an unsigned char that we can use
  13264. X   as an array index (in, e.g., `translate').  */
  13265. X#define PATFETCH(c)                            \
  13266. X  do {if (p == pend) return REG_EEND;                    \
  13267. X    c = (unsigned char) *p++;                        \
  13268. X    if (translate) c = translate[c];                     \
  13269. X  } while (0)
  13270. X
  13271. X/* Fetch the next character in the uncompiled pattern, with no
  13272. X   translation.  */
  13273. X#define PATFETCH_RAW(c)                            \
  13274. X  do {if (p == pend) return REG_EEND;                    \
  13275. X    c = (unsigned char) *p++;                         \
  13276. X  } while (0)
  13277. X
  13278. X/* Go backwards one character in the pattern.  */
  13279. X#define PATUNFETCH p--
  13280. X
  13281. X
  13282. X/* If `translate' is non-null, return translate[D], else just D.  We
  13283. X   cast the subscript to translate because some data is declared as
  13284. X   `char *', to avoid warnings when a string constant is passed.  But
  13285. X   when we use a character as a subscript we must make it unsigned.  */
  13286. X#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
  13287. X
  13288. X
  13289. X/* Macros for outputting the compiled pattern into `buffer'.  */
  13290. X
  13291. X/* If the buffer isn't allocated when it comes in, use this.  */
  13292. X#define INIT_BUF_SIZE  32
  13293. X
  13294. X/* Make sure we have at least N more bytes of space in buffer.  */
  13295. X#define GET_BUFFER_SPACE(n)                        \
  13296. X    while (b - bufp->buffer + (n) > bufp->allocated)            \
  13297. X      EXTEND_BUFFER ()
  13298. X
  13299. X/* Make sure we have one more byte of buffer space and then add C to it.  */
  13300. X#define BUF_PUSH(c)                            \
  13301. X  do {                                    \
  13302. X    GET_BUFFER_SPACE (1);                        \
  13303. X    *b++ = (unsigned char) (c);                        \
  13304. X  } while (0)
  13305. X
  13306. X
  13307. X/* Ensure we have two more bytes of buffer space and then append C1 and C2.  */
  13308. X#define BUF_PUSH_2(c1, c2)                        \
  13309. X  do {                                    \
  13310. X    GET_BUFFER_SPACE (2);                        \
  13311. X    *b++ = (unsigned char) (c1);                    \
  13312. X    *b++ = (unsigned char) (c2);                    \
  13313. X  } while (0)
  13314. X
  13315. X
  13316. X/* As with BUF_PUSH_2, except for three bytes.  */
  13317. X#define BUF_PUSH_3(c1, c2, c3)                        \
  13318. X  do {                                    \
  13319. X    GET_BUFFER_SPACE (3);                        \
  13320. X    *b++ = (unsigned char) (c1);                    \
  13321. X    *b++ = (unsigned char) (c2);                    \
  13322. X    *b++ = (unsigned char) (c3);                    \
  13323. X  } while (0)
  13324. X
  13325. X
  13326. X/* Store a jump with opcode OP at LOC to location TO.  We store a
  13327. X   relative address offset by the three bytes the jump itself occupies.  */
  13328. X#define STORE_JUMP(op, loc, to) \
  13329. X  store_op1 (op, loc, (to) - (loc) - 3)
  13330. X
  13331. X/* Likewise, for a two-argument jump.  */
  13332. X#define STORE_JUMP2(op, loc, to, arg) \
  13333. X  store_op2 (op, loc, (to) - (loc) - 3, arg)
  13334. X
  13335. X/* Like `STORE_JUMP', but for inserting.  Assume `b' is the buffer end.  */
  13336. X#define INSERT_JUMP(op, loc, to) \
  13337. X  insert_op1 (op, loc, (to) - (loc) - 3, b)
  13338. X
  13339. X/* Like `STORE_JUMP2', but for inserting.  Assume `b' is the buffer end.  */
  13340. X#define INSERT_JUMP2(op, loc, to, arg) \
  13341. X  insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
  13342. X
  13343. X
  13344. X/* This is not an arbitrary limit: the arguments which represent offsets
  13345. X   into the pattern are two bytes long.  So if 2^16 bytes turns out to
  13346. X   be too small, many things would have to change.  */
  13347. X#define MAX_BUF_SIZE (1L << 16)
  13348. X
  13349. X
  13350. X/* Extend the buffer by twice its current size via realloc and
  13351. X   reset the pointers that pointed into the old block to point to the
  13352. X   correct places in the new one.  If extending the buffer results in it
  13353. X   being larger than MAX_BUF_SIZE, then flag memory exhausted.  */
  13354. X#define EXTEND_BUFFER()                            \
  13355. X  do {                                     \
  13356. X    unsigned char *old_buffer = bufp->buffer;                \
  13357. X    if (bufp->allocated == MAX_BUF_SIZE)                 \
  13358. X      return REG_ESIZE;                            \
  13359. X    bufp->allocated <<= 1;                        \
  13360. X    if (bufp->allocated > MAX_BUF_SIZE)                    \
  13361. X      bufp->allocated = MAX_BUF_SIZE;                     \
  13362. X    bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
  13363. X    if (bufp->buffer == NULL)                        \
  13364. X      return REG_ESPACE;                        \
  13365. X    /* If the buffer moved, move all the pointers into it.  */        \
  13366. X    if (old_buffer != bufp->buffer)                    \
  13367. X      {                                    \
  13368. X        b = (b - old_buffer) + bufp->buffer;                \
  13369. X        begalt = (begalt - old_buffer) + bufp->buffer;            \
  13370. X        if (fixup_alt_jump)                        \
  13371. X          fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
  13372. X        if (laststart)                            \
  13373. X          laststart = (laststart - old_buffer) + bufp->buffer;        \
  13374. X        if (pending_exact)                        \
  13375. X          pending_exact = (pending_exact - old_buffer) + bufp->buffer;    \
  13376. X      }                                    \
  13377. X  } while (0)
  13378. X
  13379. X
  13380. X/* Since we have one byte reserved for the register number argument to
  13381. X   {start,stop}_memory, the maximum number of groups we can report
  13382. X   things about is what fits in that byte.  */
  13383. X#define MAX_REGNUM 255
  13384. X
  13385. X/* But patterns can have more than `MAX_REGNUM' registers.  We just
  13386. X   ignore the excess.  */
  13387. Xtypedef unsigned regnum_t;
  13388. X
  13389. X
  13390. X/* Macros for the compile stack.  */
  13391. X
  13392. X/* Since offsets can go either forwards or backwards, this type needs to
  13393. X   be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1.  */
  13394. Xtypedef int pattern_offset_t;
  13395. X
  13396. Xtypedef struct
  13397. X{
  13398. X  pattern_offset_t begalt_offset;
  13399. X  pattern_offset_t fixup_alt_jump;
  13400. X  pattern_offset_t inner_group_offset;
  13401. X  pattern_offset_t laststart_offset;  
  13402. X  regnum_t regnum;
  13403. X} compile_stack_elt_t;
  13404. X
  13405. X
  13406. Xtypedef struct
  13407. X{
  13408. X  compile_stack_elt_t *stack;
  13409. X  unsigned size;
  13410. X  unsigned avail;            /* Offset of next open position.  */
  13411. X} compile_stack_type;
  13412. X
  13413. X
  13414. X#define INIT_COMPILE_STACK_SIZE 32
  13415. X
  13416. X#define COMPILE_STACK_EMPTY  (compile_stack.avail == 0)
  13417. X#define COMPILE_STACK_FULL  (compile_stack.avail == compile_stack.size)
  13418. X
  13419. X/* The next available element.  */
  13420. X#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
  13421. X
  13422. X
  13423. X/* Set the bit for character C in a list.  */
  13424. X#define SET_LIST_BIT(c)                               \
  13425. X  (b[((unsigned char) (c)) / BYTEWIDTH]               \
  13426. X   |= 1 << (((unsigned char) c) % BYTEWIDTH))
  13427. X
  13428. X
  13429. X/* Get the next unsigned number in the uncompiled pattern.  */
  13430. X#define GET_UNSIGNED_NUMBER(num)                     \
  13431. X  { if (p != pend)                            \
  13432. X     {                                    \
  13433. X       PATFETCH (c);                             \
  13434. X       while (ISDIGIT (c))                         \
  13435. X         {                                 \
  13436. X           if (num < 0)                            \
  13437. X              num = 0;                            \
  13438. X           num = num * 10 + c - '0';                     \
  13439. X           if (p == pend)                         \
  13440. X              break;                             \
  13441. X           PATFETCH (c);                        \
  13442. X         }                                 \
  13443. X       }                                 \
  13444. X    }        
  13445. X
  13446. X#define CHAR_CLASS_MAX_LENGTH  6 /* Namely, `xdigit'.  */
  13447. X
  13448. X#define IS_CHAR_CLASS(string)                        \
  13449. X   (STREQ (string, "alpha") || STREQ (string, "upper")            \
  13450. X    || STREQ (string, "lower") || STREQ (string, "digit")        \
  13451. X    || STREQ (string, "alnum") || STREQ (string, "xdigit")        \
  13452. X    || STREQ (string, "space") || STREQ (string, "print")        \
  13453. X    || STREQ (string, "punct") || STREQ (string, "graph")        \
  13454. X    || STREQ (string, "cntrl") || STREQ (string, "blank"))
  13455. X
  13456. X/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
  13457. X   Returns one of error codes defined in `regex.h', or zero for success.
  13458. X
  13459. X   Assumes the `allocated' (and perhaps `buffer') and `translate'
  13460. X   fields are set in BUFP on entry.
  13461. X
  13462. X   If it succeeds, results are put in BUFP (if it returns an error, the
  13463. X   contents of BUFP are undefined):
  13464. X     `buffer' is the compiled pattern;
  13465. X     `syntax' is set to SYNTAX;
  13466. X     `used' is set to the length of the compiled pattern;
  13467. X     `fastmap_accurate' is zero;
  13468. X     `re_nsub' is the number of subexpressions in PATTERN;
  13469. X     `not_bol' and `not_eol' are zero;
  13470. X   
  13471. X   The `fastmap' and `newline_anchor' fields are neither
  13472. X   examined nor set.  */
  13473. X
  13474. Xstatic reg_errcode_t
  13475. Xregex_compile (pattern, size, syntax, bufp)
  13476. X     const char *pattern;
  13477. X     int size;
  13478. X     reg_syntax_t syntax;
  13479. X     struct re_pattern_buffer *bufp;
  13480. X{
  13481. X  /* We fetch characters from PATTERN here.  Even though PATTERN is
  13482. X     `char *' (i.e., signed), we declare these variables as unsigned, so
  13483. X     they can be reliably used as array indices.  */
  13484. X  register unsigned char c, c1;
  13485. X  
  13486. X  /* A random tempory spot in PATTERN.  */
  13487. X  const char *p1;
  13488. X
  13489. X  /* Points to the end of the buffer, where we should append.  */
  13490. X  register unsigned char *b;
  13491. X  
  13492. X  /* Keeps track of unclosed groups.  */
  13493. X  compile_stack_type compile_stack;
  13494. X
  13495. X  /* Points to the current (ending) position in the pattern.  */
  13496. X  const char *p = pattern;
  13497. X  const char *pend = pattern + size;
  13498. X  
  13499. X  /* How to translate the characters in the pattern.  */
  13500. X  char *translate = bufp->translate;
  13501. X
  13502. X  /* Address of the count-byte of the most recently inserted `exactn'
  13503. X     command.  This makes it possible to tell if a new exact-match
  13504. X     character can be added to that command or if the character requires
  13505. X     a new `exactn' command.  */
  13506. X  unsigned char *pending_exact = 0;
  13507. X
  13508. X  /* Address of start of the most recently finished expression.
  13509. X     This tells, e.g., postfix * where to find the start of its
  13510. X     operand.  Reset at the beginning of groups and alternatives.  */
  13511. X  unsigned char *laststart = 0;
  13512. X
  13513. X  /* Address of beginning of regexp, or inside of last group.  */
  13514. X  unsigned char *begalt;
  13515. X
  13516. X  /* Place in the uncompiled pattern (i.e., the {) to
  13517. X     which to go back if the interval is invalid.  */
  13518. X  const char *beg_interval;
  13519. X                
  13520. X  /* Address of the place where a forward jump should go to the end of
  13521. X     the containing expression.  Each alternative of an `or' -- except the
  13522. X     last -- ends with a forward jump of this sort.  */
  13523. X  unsigned char *fixup_alt_jump = 0;
  13524. X
  13525. X  /* Counts open-groups as they are encountered.  Remembered for the
  13526. X     matching close-group on the compile stack, so the same register
  13527. X     number is put in the stop_memory as the start_memory.  */
  13528. X  regnum_t regnum = 0;
  13529. X
  13530. X#ifdef DEBUG
  13531. X  DEBUG_PRINT1 ("\nCompiling pattern: ");
  13532. X  if (debug)
  13533. X    {
  13534. X      unsigned debug_count;
  13535. X      
  13536. X      for (debug_count = 0; debug_count < size; debug_count++)
  13537. X        printchar (pattern[debug_count]);
  13538. X      putchar ('\n');
  13539. X    }
  13540. X#endif /* DEBUG */
  13541. X
  13542. X  /* Initialize the compile stack.  */
  13543. X  compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
  13544. X  if (compile_stack.stack == NULL)
  13545. X    return REG_ESPACE;
  13546. X
  13547. X  compile_stack.size = INIT_COMPILE_STACK_SIZE;
  13548. X  compile_stack.avail = 0;
  13549. X
  13550. X  /* Initialize the pattern buffer.  */
  13551. X  bufp->syntax = syntax;
  13552. X  bufp->fastmap_accurate = 0;
  13553. X  bufp->not_bol = bufp->not_eol = 0;
  13554. X
  13555. X  /* Set `used' to zero, so that if we return an error, the pattern
  13556. X     printer (for debugging) will think there's no pattern.  We reset it
  13557. X     at the end.  */
  13558. X  bufp->used = 0;
  13559. X  
  13560. X  /* Always count groups, whether or not bufp->no_sub is set.  */
  13561. X  bufp->re_nsub = 0;                
  13562. X
  13563. X#if !defined (emacs) && !defined (SYNTAX_TABLE)
  13564. X  /* Initialize the syntax table.  */
  13565. X   init_syntax_once ();
  13566. X#endif
  13567. X
  13568. X  if (bufp->allocated == 0)
  13569. X    {
  13570. X      if (bufp->buffer)
  13571. X    { /* If zero allocated, but buffer is non-null, try to realloc
  13572. X             enough space.  This loses if buffer's address is bogus, but
  13573. X             that is the user's responsibility.  */
  13574. X          RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
  13575. X        }
  13576. X      else
  13577. X        { /* Caller did not allocate a buffer.  Do it for them.  */
  13578. X          bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
  13579. X        }
  13580. X      if (!bufp->buffer) return REG_ESPACE;
  13581. X
  13582. X      bufp->allocated = INIT_BUF_SIZE;
  13583. X    }
  13584. X
  13585. X  begalt = b = bufp->buffer;
  13586. X
  13587. X  /* Loop through the uncompiled pattern until we're at the end.  */
  13588. X  while (p != pend)
  13589. X    {
  13590. X      PATFETCH (c);
  13591. X
  13592. X      switch (c)
  13593. X        {
  13594. X        case '^':
  13595. X          {
  13596. X            if (   /* If at start of pattern, it's an operator.  */
  13597. X                   p == pattern + 1
  13598. X                   /* If context independent, it's an operator.  */
  13599. X                || syntax & RE_CONTEXT_INDEP_ANCHORS
  13600. X                   /* Otherwise, depends on what's come before.  */
  13601. X                || at_begline_loc_p (pattern, p, syntax))
  13602. X              BUF_PUSH (begline);
  13603. X            else
  13604. X              goto normal_char;
  13605. X          }
  13606. X          break;
  13607. X
  13608. X
  13609. X        case '$':
  13610. X          {
  13611. X            if (   /* If at end of pattern, it's an operator.  */
  13612. X                   p == pend 
  13613. X                   /* If context independent, it's an operator.  */
  13614. X                || syntax & RE_CONTEXT_INDEP_ANCHORS
  13615. X                   /* Otherwise, depends on what's next.  */
  13616. X                || at_endline_loc_p (p, pend, syntax))
  13617. X               BUF_PUSH (endline);
  13618. X             else
  13619. X               goto normal_char;
  13620. X           }
  13621. X           break;
  13622. X
  13623. X
  13624. X    case '+':
  13625. X        case '?':
  13626. X          if ((syntax & RE_BK_PLUS_QM)
  13627. X              || (syntax & RE_LIMITED_OPS))
  13628. X            goto normal_char;
  13629. X        handle_plus:
  13630. X        case '*':
  13631. X          /* If there is no previous pattern... */
  13632. X          if (!laststart)
  13633. X            {
  13634. X              if (syntax & RE_CONTEXT_INVALID_OPS)
  13635. X                return REG_BADRPT;
  13636. X              else if (!(syntax & RE_CONTEXT_INDEP_OPS))
  13637. X                goto normal_char;
  13638. X            }
  13639. X
  13640. X          {
  13641. X            /* Are we optimizing this jump?  */
  13642. X            boolean keep_string_p = false;
  13643. X            
  13644. X            /* 1 means zero (many) matches is allowed.  */
  13645. X            char zero_times_ok = 0, many_times_ok = 0;
  13646. X
  13647. X            /* If there is a sequence of repetition chars, collapse it
  13648. X               down to just one (the right one).  We can't combine
  13649. X               interval operators with these because of, e.g., `a{2}*',
  13650. X               which should only match an even number of `a's.  */
  13651. X
  13652. X            for (;;)
  13653. X              {
  13654. X                zero_times_ok |= c != '+';
  13655. X                many_times_ok |= c != '?';
  13656. X
  13657. X                if (p == pend)
  13658. X                  break;
  13659. X
  13660. X                PATFETCH (c);
  13661. X
  13662. X                if (c == '*'
  13663. X                    || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
  13664. X                  ;
  13665. X
  13666. X                else if (syntax & RE_BK_PLUS_QM  &&  c == '\\')
  13667. X                  {
  13668. X                    if (p == pend) return REG_EESCAPE;
  13669. X
  13670. X                    PATFETCH (c1);
  13671. X                    if (!(c1 == '+' || c1 == '?'))
  13672. X                      {
  13673. X                        PATUNFETCH;
  13674. X                        PATUNFETCH;
  13675. X                        break;
  13676. X                      }
  13677. X
  13678. X                    c = c1;
  13679. X                  }
  13680. X                else
  13681. X                  {
  13682. X                    PATUNFETCH;
  13683. X                    break;
  13684. X                  }
  13685. X
  13686. X                /* If we get here, we found another repeat character.  */
  13687. X               }
  13688. X
  13689. X            /* Star, etc. applied to an empty pattern is equivalent
  13690. X               to an empty pattern.  */
  13691. X            if (!laststart)  
  13692. X              break;
  13693. X
  13694. X            /* Now we know whether or not zero matches is allowed
  13695. X               and also whether or not two or more matches is allowed.  */
  13696. X            if (many_times_ok)
  13697. X              { /* More than one repetition is allowed, so put in at the
  13698. X                   end a backward relative jump from `b' to before the next
  13699. X                   jump we're going to put in below (which jumps from
  13700. X                   laststart to after this jump).  
  13701. X
  13702. X                   But if we are at the `*' in the exact sequence `.*\n',
  13703. X                   insert an unconditional jump backwards to the .,
  13704. X                   instead of the beginning of the loop.  This way we only
  13705. X                   push a failure point once, instead of every time
  13706. X                   through the loop.  */
  13707. X                assert (p - 1 > pattern);
  13708. X
  13709. X                /* Allocate the space for the jump.  */
  13710. X                GET_BUFFER_SPACE (3);
  13711. X
  13712. X                /* We know we are not at the first character of the pattern,
  13713. X                   because laststart was nonzero.  And we've already
  13714. X                   incremented `p', by the way, to be the character after
  13715. X                   the `*'.  Do we have to do something analogous here
  13716. X                   for null bytes, because of RE_DOT_NOT_NULL?  */
  13717. X                if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
  13718. X                    && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
  13719. X                    && !(syntax & RE_DOT_NEWLINE))
  13720. X                  { /* We have .*\n.  */
  13721. X                    STORE_JUMP (jump, b, laststart);
  13722. X                    keep_string_p = true;
  13723. X                  }
  13724. X                else
  13725. X                  /* Anything else.  */
  13726. X                  STORE_JUMP (maybe_pop_jump, b, laststart - 3);
  13727. X
  13728. X                /* We've added more stuff to the buffer.  */
  13729. X                b += 3;
  13730. X              }
  13731. X
  13732. X            /* On failure, jump from laststart to b + 3, which will be the
  13733. X               end of the buffer after this jump is inserted.  */
  13734. X            GET_BUFFER_SPACE (3);
  13735. X            INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
  13736. X                                       : on_failure_jump,
  13737. X                         laststart, b + 3);
  13738. X            pending_exact = 0;
  13739. X            b += 3;
  13740. X
  13741. X            if (!zero_times_ok)
  13742. X              {
  13743. X                /* At least one repetition is required, so insert a
  13744. X                   `dummy_failure_jump' before the initial
  13745. X                   `on_failure_jump' instruction of the loop. This
  13746. X                   effects a skip over that instruction the first time
  13747. X                   we hit that loop.  */
  13748. X                GET_BUFFER_SPACE (3);
  13749. X                INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
  13750. X                b += 3;
  13751. X              }
  13752. X            }
  13753. X      break;
  13754. X
  13755. X
  13756. X    case '.':
  13757. X          laststart = b;
  13758. X          BUF_PUSH (anychar);
  13759. X          break;
  13760. X
  13761. X
  13762. X        case '[':
  13763. X          {
  13764. X            boolean had_char_class = false;
  13765. X
  13766. X            if (p == pend) return REG_EBRACK;
  13767. X
  13768. X            /* Ensure that we have enough space to push a charset: the
  13769. X               opcode, the length count, and the bitset; 34 bytes in all.  */
  13770. X        GET_BUFFER_SPACE (34);
  13771. X
  13772. X            laststart = b;
  13773. X
  13774. X            /* We test `*p == '^' twice, instead of using an if
  13775. X               statement, so we only need one BUF_PUSH.  */
  13776. X            BUF_PUSH (*p == '^' ? charset_not : charset); 
  13777. X            if (*p == '^')
  13778. X              p++;
  13779. X
  13780. X            /* Remember the first position in the bracket expression.  */
  13781. X            p1 = p;
  13782. X
  13783. X            /* Push the number of bytes in the bitmap.  */
  13784. X            BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
  13785. X
  13786. X            /* Clear the whole map.  */
  13787. X            bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
  13788. X
  13789. X            /* charset_not matches newline according to a syntax bit.  */
  13790. X            if ((re_opcode_t) b[-2] == charset_not
  13791. X                && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
  13792. X              SET_LIST_BIT ('\n');
  13793. X
  13794. X            /* Read in characters and ranges, setting map bits.  */
  13795. X            for (;;)
  13796. X              {
  13797. X                if (p == pend) return REG_EBRACK;
  13798. X
  13799. X                PATFETCH (c);
  13800. X
  13801. X                /* \ might escape characters inside [...] and [^...].  */
  13802. X                if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
  13803. X                  {
  13804. X                    if (p == pend) return REG_EESCAPE;
  13805. X
  13806. X                    PATFETCH (c1);
  13807. X                    SET_LIST_BIT (c1);
  13808. X                    continue;
  13809. X                  }
  13810. X
  13811. X                /* Could be the end of the bracket expression.  If it's
  13812. X                   not (i.e., when the bracket expression is `[]' so
  13813. X                   far), the ']' character bit gets set way below.  */
  13814. X                if (c == ']' && p != p1 + 1)
  13815. X                  break;
  13816. X
  13817. X                /* Look ahead to see if it's a range when the last thing
  13818. X                   was a character class.  */
  13819. X                if (had_char_class && c == '-' && *p != ']')
  13820. X                  return REG_ERANGE;
  13821. X
  13822. X                /* Look ahead to see if it's a range when the last thing
  13823. X                   was a character: if this is a hyphen not at the
  13824. X                   beginning or the end of a list, then it's the range
  13825. X                   operator.  */
  13826. X                if (c == '-' 
  13827. X                    && !(p - 2 >= pattern && p[-2] == '[') 
  13828. X                    && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
  13829. X                    && *p != ']')
  13830. X                  {
  13831. X                    reg_errcode_t ret
  13832. X                      = compile_range (&p, pend, translate, syntax, b);
  13833. X                    if (ret != REG_NOERROR) return ret;
  13834. X                  }
  13835. X
  13836. X                else if (p[0] == '-' && p[1] != ']')
  13837. X                  { /* This handles ranges made up of characters only.  */
  13838. X                    reg_errcode_t ret;
  13839. X
  13840. X            /* Move past the `-'.  */
  13841. X                    PATFETCH (c1);
  13842. X                    
  13843. X                    ret = compile_range (&p, pend, translate, syntax, b);
  13844. X                    if (ret != REG_NOERROR) return ret;
  13845. X                  }
  13846. X
  13847. X                /* See if we're at the beginning of a possible character
  13848. X                   class.  */
  13849. X
  13850. X                else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
  13851. X                  { /* Leave room for the null.  */
  13852. X                    char str[CHAR_CLASS_MAX_LENGTH + 1];
  13853. X
  13854. X                    PATFETCH (c);
  13855. X                    c1 = 0;
  13856. X
  13857. X                    /* If pattern is `[[:'.  */
  13858. X                    if (p == pend) return REG_EBRACK;
  13859. X
  13860. X                    for (;;)
  13861. X                      {
  13862. X                        PATFETCH (c);
  13863. X                        if (c == ':' || c == ']' || p == pend
  13864. X                            || c1 == CHAR_CLASS_MAX_LENGTH)
  13865. X                          break;
  13866. X                        str[c1++] = c;
  13867. X                      }
  13868. X                    str[c1] = '\0';
  13869. X
  13870. X                    /* If isn't a word bracketed by `[:' and:`]':
  13871. X                       undo the ending character, the letters, and leave 
  13872. X                       the leading `:' and `[' (but set bits for them).  */
  13873. X                    if (c == ':' && *p == ']')
  13874. X                      {
  13875. X                        int ch;
  13876. X                        boolean is_alnum = STREQ (str, "alnum");
  13877. X                        boolean is_alpha = STREQ (str, "alpha");
  13878. X                        boolean is_blank = STREQ (str, "blank");
  13879. X                        boolean is_cntrl = STREQ (str, "cntrl");
  13880. X                        boolean is_digit = STREQ (str, "digit");
  13881. X                        boolean is_graph = STREQ (str, "graph");
  13882. X                        boolean is_lower = STREQ (str, "lower");
  13883. X                        boolean is_print = STREQ (str, "print");
  13884. X                        boolean is_punct = STREQ (str, "punct");
  13885. X                        boolean is_space = STREQ (str, "space");
  13886. X                        boolean is_upper = STREQ (str, "upper");
  13887. X                        boolean is_xdigit = STREQ (str, "xdigit");
  13888. X                        
  13889. X                        if (!IS_CHAR_CLASS (str)) return REG_ECTYPE;
  13890. X
  13891. X                        /* Throw away the ] at the end of the character
  13892. X                           class.  */
  13893. X                        PATFETCH (c);                    
  13894. X
  13895. X                        if (p == pend) return REG_EBRACK;
  13896. X
  13897. X                        for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
  13898. X                          {
  13899. X                            if (   (is_alnum  && ISALNUM (ch))
  13900. X                                || (is_alpha  && ISALPHA (ch))
  13901. X                                || (is_blank  && ISBLANK (ch))
  13902. X                                || (is_cntrl  && ISCNTRL (ch))
  13903. X                                || (is_digit  && ISDIGIT (ch))
  13904. X                                || (is_graph  && ISGRAPH (ch))
  13905. X                                || (is_lower  && ISLOWER (ch))
  13906. X                                || (is_print  && ISPRINT (ch))
  13907. X                                || (is_punct  && ISPUNCT (ch))
  13908. X                                || (is_space  && ISSPACE (ch))
  13909. X                                || (is_upper  && ISUPPER (ch))
  13910. X                                || (is_xdigit && ISXDIGIT (ch)))
  13911. X                            SET_LIST_BIT (ch);
  13912. X                          }
  13913. X                        had_char_class = true;
  13914. X                      }
  13915. X                    else
  13916. X                      {
  13917. X                        c1++;
  13918. X                        while (c1--)    
  13919. X                          PATUNFETCH;
  13920. X                        SET_LIST_BIT ('[');
  13921. X                        SET_LIST_BIT (':');
  13922. X                        had_char_class = false;
  13923. X                      }
  13924. X                  }
  13925. X                else
  13926. X                  {
  13927. X                    had_char_class = false;
  13928. X                    SET_LIST_BIT (c);
  13929. X                  }
  13930. X              }
  13931. X
  13932. X            /* Discard any (non)matching list bytes that are all 0 at the
  13933. X               end of the map.  Decrease the map-length byte too.  */
  13934. X            while ((int) b[-1] > 0 && b[b[-1] - 1] == 0) 
  13935. X              b[-1]--; 
  13936. X            b += b[-1];
  13937. X          }
  13938. X          break;
  13939. X
  13940. X
  13941. X    case '(':
  13942. X          if (syntax & RE_NO_BK_PARENS)
  13943. X            goto handle_open;
  13944. X          else
  13945. X            goto normal_char;
  13946. X
  13947. X
  13948. X        case ')':
  13949. X          if (syntax & RE_NO_BK_PARENS)
  13950. X            goto handle_close;
  13951. X          else
  13952. X            goto normal_char;
  13953. X
  13954. X
  13955. X        case '\n':
  13956. X          if (syntax & RE_NEWLINE_ALT)
  13957. X            goto handle_alt;
  13958. X          else
  13959. X            goto normal_char;
  13960. X
  13961. X
  13962. X    case '|':
  13963. X          if (syntax & RE_NO_BK_VBAR)
  13964. X            goto handle_alt;
  13965. X          else
  13966. X            goto normal_char;
  13967. X
  13968. X
  13969. X        case '{':
  13970. X           if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
  13971. X             goto handle_interval;
  13972. X           else
  13973. X             goto normal_char;
  13974. X
  13975. X
  13976. X        case '\\':
  13977. X          if (p == pend) return REG_EESCAPE;
  13978. X
  13979. X          /* Do not translate the character after the \, so that we can
  13980. X             distinguish, e.g., \B from \b, even if we normally would
  13981. X             translate, e.g., B to b.  */
  13982. X          PATFETCH_RAW (c);
  13983. X
  13984. X          switch (c)
  13985. X            {
  13986. X            case '(':
  13987. X              if (syntax & RE_NO_BK_PARENS)
  13988. X                goto normal_backslash;
  13989. X
  13990. X            handle_open:
  13991. X              bufp->re_nsub++;
  13992. X              regnum++;
  13993. X
  13994. X              if (COMPILE_STACK_FULL)
  13995. X                { 
  13996. X                  RETALLOC (compile_stack.stack, compile_stack.size << 1,
  13997. X                            compile_stack_elt_t);
  13998. X                  if (compile_stack.stack == NULL) return REG_ESPACE;
  13999. X
  14000. X                  compile_stack.size <<= 1;
  14001. X                }
  14002. X
  14003. X              /* These are the values to restore when we hit end of this
  14004. X                 group.  They are all relative offsets, so that if the
  14005. X                 whole pattern moves because of realloc, they will still
  14006. X                 be valid.  */
  14007. X              COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
  14008. X              COMPILE_STACK_TOP.fixup_alt_jump 
  14009. X                = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
  14010. X              COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
  14011. X              COMPILE_STACK_TOP.regnum = regnum;
  14012. X
  14013. X              /* We will eventually replace the 0 with the number of
  14014. X                 groups inner to this one.  But do not push a
  14015. X                 start_memory for groups beyond the last one we can
  14016. X                 represent in the compiled pattern.  */
  14017. X              if (regnum <= MAX_REGNUM)
  14018. X                {
  14019. X                  COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
  14020. X                  BUF_PUSH_3 (start_memory, regnum, 0);
  14021. X                }
  14022. X                
  14023. X              compile_stack.avail++;
  14024. X
  14025. X              fixup_alt_jump = 0;
  14026. X              laststart = 0;
  14027. X              begalt = b;
  14028. X              break;
  14029. X
  14030. X
  14031. X            case ')':
  14032. X              if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
  14033. X
  14034. X              if (COMPILE_STACK_EMPTY)
  14035. X                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
  14036. X                  goto normal_backslash;
  14037. X                else
  14038. X                  return REG_ERPAREN;
  14039. X
  14040. X            handle_close:
  14041. X              if (fixup_alt_jump)
  14042. X                { /* Push a dummy failure point at the end of the
  14043. X                     alternative for a possible future
  14044. X                     `pop_failure_jump' to pop.  See comments at
  14045. X                     `push_dummy_failure' in `re_match_2'.  */
  14046. X                  BUF_PUSH (push_dummy_failure);
  14047. X                  
  14048. X                  /* We allocated space for this jump when we assigned
  14049. X                     to `fixup_alt_jump', in the `handle_alt' case below.  */
  14050. X                  STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
  14051. X                }
  14052. X
  14053. X              /* See similar code for backslashed left paren above.  */
  14054. X              if (COMPILE_STACK_EMPTY)
  14055. X                if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
  14056. X                  goto normal_char;
  14057. X                else
  14058. X                  return REG_ERPAREN;
  14059. X
  14060. X              /* Since we just checked for an empty stack above, this
  14061. X                 ``can't happen''.  */
  14062. X              assert (compile_stack.avail != 0);
  14063. X              {
  14064. X                /* We don't just want to restore into `regnum', because
  14065. X                   later groups should continue to be numbered higher,
  14066. X                   as in `(ab)c(de)' -- the second group is #2.  */
  14067. X                regnum_t this_group_regnum;
  14068. X
  14069. X                compile_stack.avail--;        
  14070. X                begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
  14071. X                fixup_alt_jump
  14072. X                  = COMPILE_STACK_TOP.fixup_alt_jump
  14073. X                    ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1 
  14074. X                    : 0;
  14075. X                laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
  14076. X                this_group_regnum = COMPILE_STACK_TOP.regnum;
  14077. X
  14078. X                /* We're at the end of the group, so now we know how many
  14079. X                   groups were inside this one.  */
  14080. X                if (this_group_regnum <= MAX_REGNUM)
  14081. X                  {
  14082. X                    unsigned char *inner_group_loc
  14083. X                      = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
  14084. X                    
  14085. X                    *inner_group_loc = regnum - this_group_regnum;
  14086. X                    BUF_PUSH_3 (stop_memory, this_group_regnum,
  14087. X                                regnum - this_group_regnum);
  14088. X                  }
  14089. X              }
  14090. X              break;
  14091. X
  14092. X
  14093. X            case '|':                    /* `\|'.  */
  14094. X              if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
  14095. X                goto normal_backslash;
  14096. X            handle_alt:
  14097. X              if (syntax & RE_LIMITED_OPS)
  14098. X                goto normal_char;
  14099. X
  14100. X              /* Insert before the previous alternative a jump which
  14101. X                 jumps to this alternative if the former fails.  */
  14102. X              GET_BUFFER_SPACE (3);
  14103. X              INSERT_JUMP (on_failure_jump, begalt, b + 6);
  14104. X              pending_exact = 0;
  14105. X              b += 3;
  14106. X
  14107. X              /* The alternative before this one has a jump after it
  14108. X                 which gets executed if it gets matched.  Adjust that
  14109. X                 jump so it will jump to this alternative's analogous
  14110. X                 jump (put in below, which in turn will jump to the next
  14111. X                 (if any) alternative's such jump, etc.).  The last such
  14112. X                 jump jumps to the correct final destination.  A picture:
  14113. X                          _____ _____ 
  14114. X                          |   | |   |   
  14115. X                          |   v |   v 
  14116. X                         a | b   | c   
  14117. X
  14118. X                 If we are at `b', then fixup_alt_jump right now points to a
  14119. X                 three-byte space after `a'.  We'll put in the jump, set
  14120. X                 fixup_alt_jump to right after `b', and leave behind three
  14121. X                 bytes which we'll fill in when we get to after `c'.  */
  14122. X
  14123. X              if (fixup_alt_jump)
  14124. X                STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
  14125. X
  14126. X              /* Mark and leave space for a jump after this alternative,
  14127. X                 to be filled in later either by next alternative or
  14128. X                 when know we're at the end of a series of alternatives.  */
  14129. X              fixup_alt_jump = b;
  14130. X              GET_BUFFER_SPACE (3);
  14131. X              b += 3;
  14132. X
  14133. X              laststart = 0;
  14134. X              begalt = b;
  14135. X              break;
  14136. X
  14137. X
  14138. X            case '{': 
  14139. X              /* If \{ is a literal.  */
  14140. X              if (!(syntax & RE_INTERVALS)
  14141. X                     /* If we're at `\{' and it's not the open-interval 
  14142. X                        operator.  */
  14143. X                  || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
  14144. X                  || (p - 2 == pattern  &&  p == pend))
  14145. X                goto normal_backslash;
  14146. X
  14147. X            handle_interval:
  14148. X              {
  14149. X                /* If got here, then the syntax allows intervals.  */
  14150. X
  14151. X                /* At least (most) this many matches must be made.  */
  14152. X                int lower_bound = -1, upper_bound = -1;
  14153. X
  14154. X                beg_interval = p - 1;
  14155. X
  14156. X                if (p == pend)
  14157. X                  {
  14158. X                    if (syntax & RE_NO_BK_BRACES)
  14159. X                      goto unfetch_interval;
  14160. X                    else
  14161. X                      return REG_EBRACE;
  14162. X                  }
  14163. X
  14164. X                GET_UNSIGNED_NUMBER (lower_bound);
  14165. X
  14166. X                if (c == ',')
  14167. X                  {
  14168. X                    GET_UNSIGNED_NUMBER (upper_bound);
  14169. X                    if (upper_bound < 0) upper_bound = RE_DUP_MAX;
  14170. X                  }
  14171. X                else
  14172. X                  /* Interval such as `{1}' => match exactly once. */
  14173. X                  upper_bound = lower_bound;
  14174. X
  14175. X                if (lower_bound < 0 || upper_bound > RE_DUP_MAX
  14176. X                    || lower_bound > upper_bound)
  14177. X                  {
  14178. X                    if (syntax & RE_NO_BK_BRACES)
  14179. X                      goto unfetch_interval;
  14180. X                    else 
  14181. X                      return REG_BADBR;
  14182. X                  }
  14183. X
  14184. X                if (!(syntax & RE_NO_BK_BRACES)) 
  14185. X                  {
  14186. X                    if (c != '\\') return REG_EBRACE;
  14187. X
  14188. X                    PATFETCH (c);
  14189. X                  }
  14190. X
  14191. X                if (c != '}')
  14192. X                  {
  14193. X                    if (syntax & RE_NO_BK_BRACES)
  14194. X                      goto unfetch_interval;
  14195. X                    else 
  14196. X                      return REG_BADBR;
  14197. X                  }
  14198. X
  14199. X                /* We just parsed a valid interval.  */
  14200. X
  14201. X                /* If it's invalid to have no preceding re.  */
  14202. X                if (!laststart)
  14203. X                  {
  14204. X                    if (syntax & RE_CONTEXT_INVALID_OPS)
  14205. X                      return REG_BADRPT;
  14206. X                    else if (syntax & RE_CONTEXT_INDEP_OPS)
  14207. X                      laststart = b;
  14208. X                    else
  14209. X                      goto unfetch_interval;
  14210. X                  }
  14211. X
  14212. X                /* If the upper bound is zero, don't want to succeed at
  14213. X                   all; jump from `laststart' to `b + 3', which will be
  14214. X                   the end of the buffer after we insert the jump.  */
  14215. X                 if (upper_bound == 0)
  14216. X                   {
  14217. X                     GET_BUFFER_SPACE (3);
  14218. X                     INSERT_JUMP (jump, laststart, b + 3);
  14219. X                     b += 3;
  14220. X                   }
  14221. X
  14222. X                 /* Otherwise, we have a nontrivial interval.  When
  14223. X                    we're all done, the pattern will look like:
  14224. X                      set_number_at <jump count> <upper bound>
  14225. X                      set_number_at <succeed_n count> <lower bound>
  14226. X                      succeed_n <after jump addr> <succed_n count>
  14227. X                      <body of loop>
  14228. X                      jump_n <succeed_n addr> <jump count>
  14229. X                    (The upper bound and `jump_n' are omitted if
  14230. X                    `upper_bound' is 1, though.)  */
  14231. X                 else 
  14232. X                   { /* If the upper bound is > 1, we need to insert
  14233. X                        more at the end of the loop.  */
  14234. X                     unsigned nbytes = 10 + (upper_bound > 1) * 10;
  14235. X
  14236. X                     GET_BUFFER_SPACE (nbytes);
  14237. X
  14238. X                     /* Initialize lower bound of the `succeed_n', even
  14239. X                        though it will be set during matching by its
  14240. X                        attendant `set_number_at' (inserted next),
  14241. X                        because `re_compile_fastmap' needs to know.
  14242. X                        Jump to the `jump_n' we might insert below.  */
  14243. X                     INSERT_JUMP2 (succeed_n, laststart,
  14244. X                                   b + 5 + (upper_bound > 1) * 5,
  14245. X                                   lower_bound);
  14246. X                     b += 5;
  14247. X
  14248. X                     /* Code to initialize the lower bound.  Insert 
  14249. X                        before the `succeed_n'.  The `5' is the last two
  14250. X                        bytes of this `set_number_at', plus 3 bytes of
  14251. X                        the following `succeed_n'.  */
  14252. X                     insert_op2 (set_number_at, laststart, 5, lower_bound, b);
  14253. X                     b += 5;
  14254. X
  14255. X                     if (upper_bound > 1)
  14256. X                       { /* More than one repetition is allowed, so
  14257. X                            append a backward jump to the `succeed_n'
  14258. X                            that starts this interval.
  14259. X                            
  14260. X                            When we've reached this during matching,
  14261. X                            we'll have matched the interval once, so
  14262. X                            jump back only `upper_bound - 1' times.  */
  14263. X                         STORE_JUMP2 (jump_n, b, laststart + 5,
  14264. X                                      upper_bound - 1);
  14265. X                         b += 5;
  14266. X
  14267. X                         /* The location we want to set is the second
  14268. X                            parameter of the `jump_n'; that is `b-2' as
  14269. X                            an absolute address.  `laststart' will be
  14270. X                            the `set_number_at' we're about to insert;
  14271. X                            `laststart+3' the number to set, the source
  14272. X                            for the relative address.  But we are
  14273. X                            inserting into the middle of the pattern --
  14274. X                            so everything is getting moved up by 5.
  14275. X                            Conclusion: (b - 2) - (laststart + 3) + 5,
  14276. X                            i.e., b - laststart.
  14277. X                            
  14278. X                            We insert this at the beginning of the loop
  14279. X                            so that if we fail during matching, we'll
  14280. X                            reinitialize the bounds.  */
  14281. X                         insert_op2 (set_number_at, laststart, b - laststart,
  14282. X                                     upper_bound - 1, b);
  14283. X                         b += 5;
  14284. X                       }
  14285. X                   }
  14286. X                pending_exact = 0;
  14287. X                beg_interval = NULL;
  14288. X              }
  14289. X              break;
  14290. X
  14291. X            unfetch_interval:
  14292. X              /* If an invalid interval, match the characters as literals.  */
  14293. X               assert (beg_interval);
  14294. X               p = beg_interval;
  14295. X               beg_interval = NULL;
  14296. X
  14297. X               /* normal_char and normal_backslash need `c'.  */
  14298. X               PATFETCH (c);    
  14299. X
  14300. X               if (!(syntax & RE_NO_BK_BRACES))
  14301. X                 {
  14302. X                   if (p > pattern  &&  p[-1] == '\\')
  14303. X                     goto normal_backslash;
  14304. X                 }
  14305. X               goto normal_char;
  14306. X
  14307. X#ifdef emacs
  14308. X            /* There is no way to specify the before_dot and after_dot
  14309. X               operators.  rms says this is ok.  --karl  */
  14310. X            case '=':
  14311. X              BUF_PUSH (at_dot);
  14312. X              break;
  14313. X
  14314. X            case 's':    
  14315. X              laststart = b;
  14316. X              PATFETCH (c);
  14317. X              BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
  14318. X              break;
  14319. X
  14320. X            case 'S':
  14321. X              laststart = b;
  14322. X              PATFETCH (c);
  14323. X              BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
  14324. X              break;
  14325. X#endif /* emacs */
  14326. X
  14327. X
  14328. X            case 'w':
  14329. X              laststart = b;
  14330. X              BUF_PUSH (wordchar);
  14331. X              break;
  14332. X
  14333. X
  14334. X            case 'W':
  14335. X              laststart = b;
  14336. X              BUF_PUSH (notwordchar);
  14337. X              break;
  14338. X
  14339. X
  14340. X            case '<':
  14341. X              BUF_PUSH (wordbeg);
  14342. X              break;
  14343. X
  14344. X            case '>':
  14345. X              BUF_PUSH (wordend);
  14346. X              break;
  14347. X
  14348. X            case 'b':
  14349. X              BUF_PUSH (wordbound);
  14350. X              break;
  14351. X
  14352. X            case 'B':
  14353. X              BUF_PUSH (notwordbound);
  14354. X              break;
  14355. X
  14356. X            case '`':
  14357. X              BUF_PUSH (begbuf);
  14358. X              break;
  14359. X
  14360. X            case '\'':
  14361. X              BUF_PUSH (endbuf);
  14362. X              break;
  14363. X
  14364. X            case '1': case '2': case '3': case '4': case '5':
  14365. X            case '6': case '7': case '8': case '9':
  14366. X              if (syntax & RE_NO_BK_REFS)
  14367. X                goto normal_char;
  14368. X
  14369. X              c1 = c - '0';
  14370. X
  14371. X              if (c1 > regnum)
  14372. X                return REG_ESUBREG;
  14373. X
  14374. X              /* Can't back reference to a subexpression if inside of it.  */
  14375. X              if (group_in_compile_stack (compile_stack, c1))
  14376. X                goto normal_char;
  14377. X
  14378. X              laststart = b;
  14379. X              BUF_PUSH_2 (duplicate, c1);
  14380. X              break;
  14381. X
  14382. X
  14383. X            case '+':
  14384. X            case '?':
  14385. X              if (syntax & RE_BK_PLUS_QM)
  14386. X                goto handle_plus;
  14387. X              else
  14388. X                goto normal_backslash;
  14389. X
  14390. X            default:
  14391. X            normal_backslash:
  14392. X              /* You might think it would be useful for \ to mean
  14393. X                 not to translate; but if we don't translate it
  14394. X                 it will never match anything.  */
  14395. X              c = TRANSLATE (c);
  14396. X              goto normal_char;
  14397. X            }
  14398. X          break;
  14399. X
  14400. X
  14401. X    default:
  14402. X        /* Expects the character in `c'.  */
  14403. X    normal_char:
  14404. X          /* If no exactn currently being built.  */
  14405. X          if (!pending_exact 
  14406. X
  14407. X              /* If last exactn not at current position.  */
  14408. X              || pending_exact + *pending_exact + 1 != b
  14409. X              
  14410. X              /* We have only one byte following the exactn for the count.  */
  14411. X          || *pending_exact == (1 << BYTEWIDTH) - 1
  14412. X
  14413. X              /* If followed by a repetition operator.  */
  14414. X              || *p == '*' || *p == '^'
  14415. X          || ((syntax & RE_BK_PLUS_QM)
  14416. X          ? *p == '\\' && (p[1] == '+' || p[1] == '?')
  14417. X          : (*p == '+' || *p == '?'))
  14418. X          || ((syntax & RE_INTERVALS)
  14419. X                  && ((syntax & RE_NO_BK_BRACES)
  14420. X              ? *p == '{'
  14421. X                      : (p[0] == '\\' && p[1] == '{'))))
  14422. X        {
  14423. X          /* Start building a new exactn.  */
  14424. X              
  14425. X              laststart = b;
  14426. X
  14427. X          BUF_PUSH_2 (exactn, 0);
  14428. X          pending_exact = b - 1;
  14429. X            }
  14430. X            
  14431. X      BUF_PUSH (c);
  14432. X          (*pending_exact)++;
  14433. X      break;
  14434. X        } /* switch (c) */
  14435. X    } /* while p != pend */
  14436. X
  14437. X  
  14438. X  /* Through the pattern now.  */
  14439. X  
  14440. X  if (fixup_alt_jump)
  14441. X    STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
  14442. X
  14443. X  if (!COMPILE_STACK_EMPTY) 
  14444. X    return REG_EPAREN;
  14445. X
  14446. X  free (compile_stack.stack);
  14447. X
  14448. X  /* We have succeeded; set the length of the buffer.  */
  14449. X  bufp->used = b - bufp->buffer;
  14450. X
  14451. X#ifdef DEBUG
  14452. X  if (debug)
  14453. X    {
  14454. X      DEBUG_PRINT1 ("\nCompiled pattern: ");
  14455. X      print_compiled_pattern (bufp);
  14456. X    }
  14457. X#endif /* DEBUG */
  14458. X
  14459. X  return REG_NOERROR;
  14460. X} /* regex_compile */
  14461. X
  14462. X/* Subroutines for `regex_compile'.  */
  14463. X
  14464. X/* Store OP at LOC followed by two-byte integer parameter ARG.  */
  14465. X
  14466. Xstatic void
  14467. Xstore_op1 (op, loc, arg)
  14468. X    re_opcode_t op;
  14469. X    unsigned char *loc;
  14470. X    int arg;
  14471. X{
  14472. X  *loc = (unsigned char) op;
  14473. X  STORE_NUMBER (loc + 1, arg);
  14474. X}
  14475. X
  14476. X
  14477. X/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2.  */
  14478. X
  14479. Xstatic void
  14480. Xstore_op2 (op, loc, arg1, arg2)
  14481. X    re_opcode_t op;
  14482. X    unsigned char *loc;
  14483. X    int arg1, arg2;
  14484. X{
  14485. X  *loc = (unsigned char) op;
  14486. X  STORE_NUMBER (loc + 1, arg1);
  14487. X  STORE_NUMBER (loc + 3, arg2);
  14488. X}
  14489. X
  14490. X
  14491. X/* Copy the bytes from LOC to END to open up three bytes of space at LOC
  14492. X   for OP followed by two-byte integer parameter ARG.  */
  14493. X
  14494. Xstatic void
  14495. Xinsert_op1 (op, loc, arg, end)
  14496. X    re_opcode_t op;
  14497. X    unsigned char *loc;
  14498. X    int arg;
  14499. X    unsigned char *end;    
  14500. X{
  14501. X  register unsigned char *pfrom = end;
  14502. X  register unsigned char *pto = end + 3;
  14503. X
  14504. X  while (pfrom != loc)
  14505. X    *--pto = *--pfrom;
  14506. X    
  14507. X  store_op1 (op, loc, arg);
  14508. X}
  14509. X
  14510. X
  14511. X/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2.  */
  14512. X
  14513. Xstatic void
  14514. Xinsert_op2 (op, loc, arg1, arg2, end)
  14515. X    re_opcode_t op;
  14516. X    unsigned char *loc;
  14517. X    int arg1, arg2;
  14518. X    unsigned char *end;    
  14519. X{
  14520. X  register unsigned char *pfrom = end;
  14521. X  register unsigned char *pto = end + 5;
  14522. X
  14523. X  while (pfrom != loc)
  14524. X    *--pto = *--pfrom;
  14525. X    
  14526. X  store_op2 (op, loc, arg1, arg2);
  14527. X}
  14528. X
  14529. X
  14530. X/* P points to just after a ^ in PATTERN.  Return true if that ^ comes
  14531. X   after an alternative or a begin-subexpression.  We assume there is at
  14532. X   least one character before the ^.  */
  14533. X
  14534. Xstatic boolean
  14535. Xat_begline_loc_p (pattern, p, syntax)
  14536. X    const char *pattern, *p;
  14537. X    reg_syntax_t syntax;
  14538. X{
  14539. X  const char *prev = p - 2;
  14540. X  boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
  14541. X  
  14542. X  return
  14543. X       /* After a subexpression?  */
  14544. X       (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
  14545. X       /* After an alternative?  */
  14546. X    || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
  14547. X}
  14548. X
  14549. X
  14550. X/* The dual of at_begline_loc_p.  This one is for $.  We assume there is
  14551. X   at least one character after the $, i.e., `P < PEND'.  */
  14552. X
  14553. Xstatic boolean
  14554. Xat_endline_loc_p (p, pend, syntax)
  14555. X    const char *p, *pend;
  14556. X    int syntax;
  14557. X{
  14558. X  const char *next = p;
  14559. X  boolean next_backslash = *next == '\\';
  14560. X  const char *next_next = p + 1 < pend ? p + 1 : NULL;
  14561. X  
  14562. X  return
  14563. X       /* Before a subexpression?  */
  14564. X       (syntax & RE_NO_BK_PARENS ? *next == ')'
  14565. X        : next_backslash && next_next && *next_next == ')')
  14566. X       /* Before an alternative?  */
  14567. X    || (syntax & RE_NO_BK_VBAR ? *next == '|'
  14568. X        : next_backslash && next_next && *next_next == '|');
  14569. X}
  14570. X
  14571. X
  14572. X/* Returns true if REGNUM is in one of COMPILE_STACK's elements and 
  14573. X   false if it's not.  */
  14574. X
  14575. Xstatic boolean
  14576. Xgroup_in_compile_stack (compile_stack, regnum)
  14577. X    compile_stack_type compile_stack;
  14578. X    regnum_t regnum;
  14579. X{
  14580. X  int this_element;
  14581. X
  14582. X  for (this_element = compile_stack.avail - 1;  
  14583. X       this_element >= 0; 
  14584. X       this_element--)
  14585. X    if (compile_stack.stack[this_element].regnum == regnum)
  14586. X      return true;
  14587. X
  14588. X  return false;
  14589. X}
  14590. X
  14591. X
  14592. X/* Read the ending character of a range (in a bracket expression) from the
  14593. X   uncompiled pattern *P_PTR (which ends at PEND).  We assume the
  14594. X   starting character is in `P[-2]'.  (`P[-1]' is the character `-'.)
  14595. X   Then we set the translation of all bits between the starting and
  14596. X   ending characters (inclusive) in the compiled pattern B.
  14597. X   
  14598. X   Return an error code.
  14599. X   
  14600. X   We use these short variable names so we can use the same macros as
  14601. X   `regex_compile' itself.  */
  14602. X
  14603. Xstatic reg_errcode_t
  14604. Xcompile_range (p_ptr, pend, translate, syntax, b)
  14605. X    const char **p_ptr, *pend;
  14606. X    char *translate;
  14607. X    reg_syntax_t syntax;
  14608. X    unsigned char *b;
  14609. X{
  14610. X  unsigned this_char;
  14611. X
  14612. X  const char *p = *p_ptr;
  14613. X  int range_start, range_end;
  14614. X  
  14615. X  if (p == pend)
  14616. X    return REG_ERANGE;
  14617. X
  14618. X  /* Even though the pattern is a signed `char *', we need to fetch
  14619. X     with unsigned char *'s; if the high bit of the pattern character
  14620. X     is set, the range endpoints will be negative if we fetch using a
  14621. X     signed char *.
  14622. X
  14623. X     We also want to fetch the endpoints without translating them; the 
  14624. X     appropriate translation is done in the bit-setting loop below.  */
  14625. X  range_start = ((unsigned char *) p)[-2];
  14626. X  range_end   = ((unsigned char *) p)[0];
  14627. X
  14628. X  /* Have to increment the pointer into the pattern string, so the
  14629. X     caller isn't still at the ending character.  */
  14630. X  (*p_ptr)++;
  14631. X
  14632. X  /* If the start is after the end, the range is empty.  */
  14633. X  if (range_start > range_end)
  14634. X    return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
  14635. X
  14636. X  /* Here we see why `this_char' has to be larger than an `unsigned
  14637. X     char' -- the range is inclusive, so if `range_end' == 0xff
  14638. X     (assuming 8-bit characters), we would otherwise go into an infinite
  14639. X     loop, since all characters <= 0xff.  */
  14640. X  for (this_char = range_start; this_char <= range_end; this_char++)
  14641. X    {
  14642. X      SET_LIST_BIT (TRANSLATE (this_char));
  14643. X    }
  14644. X  
  14645. X  return REG_NOERROR;
  14646. X}
  14647. X
  14648. X/* Failure stack declarations and macros; both re_compile_fastmap and
  14649. X   re_match_2 use a failure stack.  These have to be macros because of
  14650. X   REGEX_ALLOCATE.  */
  14651. X   
  14652. X
  14653. X/* Number of failure points for which to initially allocate space
  14654. X   when matching.  If this number is exceeded, we allocate more
  14655. X   space, so it is not a hard limit.  */
  14656. X#ifndef INIT_FAILURE_ALLOC
  14657. X#define INIT_FAILURE_ALLOC 5
  14658. X#endif
  14659. X
  14660. X/* Roughly the maximum number of failure points on the stack.  Would be
  14661. X   exactly that if always used MAX_FAILURE_SPACE each time we failed.
  14662. X   This is a variable only so users of regex can assign to it; we never
  14663. X   change it ourselves.  */
  14664. Xint re_max_failures = 2000;
  14665. X
  14666. Xtypedef const unsigned char *fail_stack_elt_t;
  14667. X
  14668. Xtypedef struct
  14669. X{
  14670. X  fail_stack_elt_t *stack;
  14671. X  unsigned size;
  14672. X  unsigned avail;            /* Offset of next open position.  */
  14673. X} fail_stack_type;
  14674. X
  14675. X#define FAIL_STACK_EMPTY()     (fail_stack.avail == 0)
  14676. X#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
  14677. X#define FAIL_STACK_FULL()      (fail_stack.avail == fail_stack.size)
  14678. X#define FAIL_STACK_TOP()       (fail_stack.stack[fail_stack.avail])
  14679. X
  14680. X
  14681. X/* Initialize `fail_stack'.  Do `return -2' if the alloc fails.  */
  14682. X
  14683. X#define INIT_FAIL_STACK()                        \
  14684. X  do {                                    \
  14685. X    fail_stack.stack = (fail_stack_elt_t *)                \
  14686. X      REGEX_ALLOCATE (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t));    \
  14687. X                                    \
  14688. X    if (fail_stack.stack == NULL)                    \
  14689. X      return -2;                            \
  14690. X                                    \
  14691. X    fail_stack.size = INIT_FAILURE_ALLOC;                \
  14692. X    fail_stack.avail = 0;                        \
  14693. X  } while (0)
  14694. X
  14695. X
  14696. X/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
  14697. X
  14698. X   Return 1 if succeeds, and 0 if either ran out of memory
  14699. X   allocating space for it or it was already too large.  
  14700. X   
  14701. X   REGEX_REALLOCATE requires `destination' be declared.   */
  14702. X
  14703. X#define DOUBLE_FAIL_STACK(fail_stack)                    \
  14704. X  ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS        \
  14705. X   ? 0                                    \
  14706. X   : ((fail_stack).stack = (fail_stack_elt_t *)                \
  14707. X        REGEX_REALLOCATE ((fail_stack).stack,                 \
  14708. X          (fail_stack).size * sizeof (fail_stack_elt_t),        \
  14709. X          ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)),    \
  14710. X                                    \
  14711. X      (fail_stack).stack == NULL                    \
  14712. X      ? 0                                \
  14713. X      : ((fail_stack).size <<= 1,                     \
  14714. X         1)))
  14715. X
  14716. X
  14717. X/* Push PATTERN_OP on FAIL_STACK. 
  14718. X
  14719. X   Return 1 if was able to do so and 0 if ran out of memory allocating
  14720. X   space to do so.  */
  14721. X#define PUSH_PATTERN_OP(pattern_op, fail_stack)                \
  14722. X  ((FAIL_STACK_FULL ()                            \
  14723. X    && !DOUBLE_FAIL_STACK (fail_stack))                    \
  14724. X    ? 0                                    \
  14725. X    : ((fail_stack).stack[(fail_stack).avail++] = pattern_op,        \
  14726. X       1))
  14727. X
  14728. X/* This pushes an item onto the failure stack.  Must be a four-byte
  14729. X   value.  Assumes the variable `fail_stack'.  Probably should only
  14730. X   be called from within `PUSH_FAILURE_POINT'.  */
  14731. X#define PUSH_FAILURE_ITEM(item)                        \
  14732. X  fail_stack.stack[fail_stack.avail++] = (fail_stack_elt_t) item
  14733. X
  14734. X/* The complement operation.  Assumes `fail_stack' is nonempty.  */
  14735. X#define POP_FAILURE_ITEM() fail_stack.stack[--fail_stack.avail]
  14736. X
  14737. X/* Used to omit pushing failure point id's when we're not debugging.  */
  14738. X#ifdef DEBUG
  14739. X#define DEBUG_PUSH PUSH_FAILURE_ITEM
  14740. X#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_ITEM ()
  14741. X#else
  14742. X#define DEBUG_PUSH(item)
  14743. X#define DEBUG_POP(item_addr)
  14744. X#endif
  14745. X
  14746. X
  14747. X/* Push the information about the state we will need
  14748. X   if we ever fail back to it.  
  14749. X   
  14750. X   Requires variables fail_stack, regstart, regend, reg_info, and
  14751. X   num_regs be declared.  DOUBLE_FAIL_STACK requires `destination' be
  14752. X   declared.
  14753. X   
  14754. X   Does `return FAILURE_CODE' if runs out of memory.  */
  14755. X
  14756. X#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code)    \
  14757. X  do {                                    \
  14758. X    char *destination;                            \
  14759. X    /* Must be int, so when we don't save any registers, the arithmetic    \
  14760. X       of 0 + -1 isn't done as unsigned.  */                \
  14761. X    int this_reg;                            \
  14762. X                                        \
  14763. X    DEBUG_STATEMENT (failure_id++);                    \
  14764. X    DEBUG_STATEMENT (nfailure_points_pushed++);                \
  14765. X    DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id);        \
  14766. X    DEBUG_PRINT2 ("  Before push, next avail: %d\n", (fail_stack).avail);\
  14767. X    DEBUG_PRINT2 ("                     size: %d\n", (fail_stack).size);\
  14768. X                                    \
  14769. X    DEBUG_PRINT2 ("  slots needed: %d\n", NUM_FAILURE_ITEMS);        \
  14770. X    DEBUG_PRINT2 ("     available: %d\n", REMAINING_AVAIL_SLOTS);    \
  14771. X                                    \
  14772. X    /* Ensure we have enough space allocated for what we will push.  */    \
  14773. X    while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS)            \
  14774. X      {                                    \
  14775. X        if (!DOUBLE_FAIL_STACK (fail_stack))            \
  14776. X          return failure_code;                        \
  14777. X                                    \
  14778. X        DEBUG_PRINT2 ("\n  Doubled stack; size now: %d\n",        \
  14779. X               (fail_stack).size);                \
  14780. X        DEBUG_PRINT2 ("  slots available: %d\n", REMAINING_AVAIL_SLOTS);\
  14781. X      }                                    \
  14782. X                                    \
  14783. X    /* Push the info, starting with the registers.  */            \
  14784. X    DEBUG_PRINT1 ("\n");                        \
  14785. X                                    \
  14786. X    for (this_reg = lowest_active_reg; this_reg <= highest_active_reg;    \
  14787. X         this_reg++)                            \
  14788. X      {                                    \
  14789. X    DEBUG_PRINT2 ("  Pushing reg: %d\n", this_reg);            \
  14790. X        DEBUG_STATEMENT (num_regs_pushed++);                \
  14791. X                                    \
  14792. X    DEBUG_PRINT2 ("    start: 0x%x\n", regstart[this_reg]);        \
  14793. X        PUSH_FAILURE_ITEM (regstart[this_reg]);                \
  14794. X                                                                        \
  14795. X    DEBUG_PRINT2 ("    end: 0x%x\n", regend[this_reg]);        \
  14796. X        PUSH_FAILURE_ITEM (regend[this_reg]);                \
  14797. X                                    \
  14798. X    DEBUG_PRINT2 ("    info: 0x%x\n      ", reg_info[this_reg]);    \
  14799. X        DEBUG_PRINT2 (" match_null=%d",                    \
  14800. X                      REG_MATCH_NULL_STRING_P (reg_info[this_reg]));    \
  14801. X        DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg]));    \
  14802. X        DEBUG_PRINT2 (" matched_something=%d",                \
  14803. X                      MATCHED_SOMETHING (reg_info[this_reg]));        \
  14804. X        DEBUG_PRINT2 (" ever_matched=%d",                \
  14805. X                      EVER_MATCHED_SOMETHING (reg_info[this_reg]));    \
  14806. X    DEBUG_PRINT1 ("\n");                        \
  14807. X        PUSH_FAILURE_ITEM (reg_info[this_reg].word);            \
  14808. X      }                                    \
  14809. X                                    \
  14810. X    DEBUG_PRINT2 ("  Pushing  low active reg: %d\n", lowest_active_reg);\
  14811. X    PUSH_FAILURE_ITEM (lowest_active_reg);                \
  14812. X                                    \
  14813. X    DEBUG_PRINT2 ("  Pushing high active reg: %d\n", highest_active_reg);\
  14814. X    PUSH_FAILURE_ITEM (highest_active_reg);                \
  14815. X                                    \
  14816. X    DEBUG_PRINT2 ("  Pushing pattern 0x%x: ", pattern_place);        \
  14817. X    DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend);        \
  14818. X    PUSH_FAILURE_ITEM (pattern_place);                    \
  14819. X                                    \
  14820. X    DEBUG_PRINT2 ("  Pushing string 0x%x: `", string_place);        \
  14821. X    DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2,   \
  14822. X                 size2);                \
  14823. X    DEBUG_PRINT1 ("'\n");                        \
  14824. X    PUSH_FAILURE_ITEM (string_place);                    \
  14825. X                                    \
  14826. X    DEBUG_PRINT2 ("  Pushing failure id: %u\n", failure_id);        \
  14827. X    DEBUG_PUSH (failure_id);                        \
  14828. X  } while (0)
  14829. X
  14830. X/* This is the number of items that are pushed and popped on the stack
  14831. X   for each register.  */
  14832. X#define NUM_REG_ITEMS  3
  14833. X
  14834. X/* Individual items aside from the registers.  */
  14835. X#ifdef DEBUG
  14836. X#define NUM_NONREG_ITEMS 5 /* Includes failure point id.  */
  14837. X#else
  14838. X#define NUM_NONREG_ITEMS 4
  14839. X#endif
  14840. X
  14841. X/* We push at most this many items on the stack.  */
  14842. X#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
  14843. X
  14844. X/* We actually push this many items.  */
  14845. X#define NUM_FAILURE_ITEMS                        \
  14846. X  ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS     \
  14847. X    + NUM_NONREG_ITEMS)
  14848. X
  14849. X/* How many items can still be added to the stack without overflowing it.  */
  14850. X#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
  14851. X
  14852. X
  14853. X/* Pops what PUSH_FAIL_STACK pushes.
  14854. X
  14855. X   We restore into the parameters, all of which should be lvalues:
  14856. X     STR -- the saved data position.
  14857. X     PAT -- the saved pattern position.
  14858. X     LOW_REG, HIGH_REG -- the highest and lowest active registers.
  14859. X     REGSTART, REGEND -- arrays of string positions.
  14860. X     REG_INFO -- array of information about each subexpression.
  14861. X   
  14862. X   Also assumes the variables `fail_stack' and (if debugging), `bufp',
  14863. X   `pend', `string1', `size1', `string2', and `size2'.  */
  14864. X
  14865. X#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
  14866. X{                                    \
  14867. X  DEBUG_STATEMENT (fail_stack_elt_t failure_id;)            \
  14868. X  int this_reg;                                \
  14869. X  const unsigned char *string_temp;                    \
  14870. X                                    \
  14871. X  assert (!FAIL_STACK_EMPTY ());                    \
  14872. X                                    \
  14873. X  /* Remove failure points and point to how many regs pushed.  */    \
  14874. X  DEBUG_PRINT1 ("POP_FAILURE_POINT:\n");                \
  14875. X  DEBUG_PRINT2 ("  Before pop, next avail: %d\n", fail_stack.avail);    \
  14876. X  DEBUG_PRINT2 ("                    size: %d\n", fail_stack.size);    \
  14877. X                                    \
  14878. X  assert (fail_stack.avail >= NUM_NONREG_ITEMS);            \
  14879. X                                    \
  14880. X  DEBUG_POP (&failure_id);                        \
  14881. X  DEBUG_PRINT2 ("  Popping failure id: %u\n", failure_id);        \
  14882. X                                    \
  14883. X  /* If the saved string location is NULL, it came from an        \
  14884. X     on_failure_keep_string_jump opcode, and we want to throw away the    \
  14885. X     saved NULL, thus retaining our current position in the string.  */    \
  14886. X  string_temp = POP_FAILURE_ITEM ();                    \
  14887. X  if (string_temp != NULL)                        \
  14888. X    str = (const char *) string_temp;                    \
  14889. X                                    \
  14890. X  DEBUG_PRINT2 ("  Popping string 0x%x: `", str);            \
  14891. X  DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2);    \
  14892. X  DEBUG_PRINT1 ("'\n");                            \
  14893. X                                    \
  14894. X  pat = (unsigned char *) POP_FAILURE_ITEM ();                \
  14895. X  DEBUG_PRINT2 ("  Popping pattern 0x%x: ", pat);            \
  14896. X  DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend);            \
  14897. X                                    \
  14898. X  /* Restore register info.  */                        \
  14899. X  high_reg = (unsigned) POP_FAILURE_ITEM ();                \
  14900. X  DEBUG_PRINT2 ("  Popping high active reg: %d\n", high_reg);        \
  14901. X                                    \
  14902. X  low_reg = (unsigned) POP_FAILURE_ITEM ();                \
  14903. X  DEBUG_PRINT2 ("  Popping  low active reg: %d\n", low_reg);        \
  14904. X                                    \
  14905. X  for (this_reg = high_reg; this_reg >= low_reg; this_reg--)        \
  14906. X    {                                    \
  14907. X      DEBUG_PRINT2 ("    Popping reg: %d\n", this_reg);            \
  14908. X                                    \
  14909. X      reg_info[this_reg].word = POP_FAILURE_ITEM ();            \
  14910. X      DEBUG_PRINT2 ("      info: 0x%x\n", reg_info[this_reg]);        \
  14911. X                                    \
  14912. X      regend[this_reg] = (const char *) POP_FAILURE_ITEM ();        \
  14913. X      DEBUG_PRINT2 ("      end: 0x%x\n", regend[this_reg]);        \
  14914. X                                    \
  14915. X      regstart[this_reg] = (const char *) POP_FAILURE_ITEM ();        \
  14916. X      DEBUG_PRINT2 ("      start: 0x%x\n", regstart[this_reg]);        \
  14917. X    }                                    \
  14918. X                                    \
  14919. X  DEBUG_STATEMENT (nfailure_points_popped++);                \
  14920. X} /* POP_FAILURE_POINT */
  14921. X
  14922. X/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
  14923. X   BUFP.  A fastmap records which of the (1 << BYTEWIDTH) possible
  14924. X   characters can start a string that matches the pattern.  This fastmap
  14925. X   is used by re_search to skip quickly over impossible starting points.
  14926. X
  14927. X   The caller must supply the address of a (1 << BYTEWIDTH)-byte data
  14928. X   area as BUFP->fastmap.
  14929. X   
  14930. X   We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
  14931. X   the pattern buffer.
  14932. X
  14933. X   Returns 0 if we succeed, -2 if an internal error.   */
  14934. X
  14935. Xint
  14936. Xre_compile_fastmap (bufp)
  14937. X     struct re_pattern_buffer *bufp;
  14938. X{
  14939. X  int j, k;
  14940. X  fail_stack_type fail_stack;
  14941. X#ifndef REGEX_MALLOC
  14942. X  char *destination;
  14943. X#endif
  14944. X  /* We don't push any register information onto the failure stack.  */
  14945. X  unsigned num_regs = 0;
  14946. X  
  14947. X  register char *fastmap = bufp->fastmap;
  14948. X  unsigned char *pattern = bufp->buffer;
  14949. X  unsigned long size = bufp->used;
  14950. X  const unsigned char *p = pattern;
  14951. X  register unsigned char *pend = pattern + size;
  14952. X
  14953. X  /* Assume that each path through the pattern can be null until
  14954. X     proven otherwise.  We set this false at the bottom of switch
  14955. X     statement, to which we get only if a particular path doesn't
  14956. X     match the empty string.  */
  14957. X  boolean path_can_be_null = true;
  14958. X
  14959. X  /* We aren't doing a `succeed_n' to begin with.  */
  14960. X  boolean succeed_n_p = false;
  14961. X
  14962. X  assert (fastmap != NULL && p != NULL);
  14963. X  
  14964. X  INIT_FAIL_STACK ();
  14965. X  bzero (fastmap, 1 << BYTEWIDTH);  /* Assume nothing's valid.  */
  14966. X  bufp->fastmap_accurate = 1;        /* It will be when we're done.  */
  14967. X  bufp->can_be_null = 0;
  14968. X      
  14969. X  while (p != pend || !FAIL_STACK_EMPTY ())
  14970. X    {
  14971. X      if (p == pend)
  14972. X        {
  14973. X          bufp->can_be_null |= path_can_be_null;
  14974. X          
  14975. X          /* Reset for next path.  */
  14976. X          path_can_be_null = true;
  14977. X          
  14978. X          p = fail_stack.stack[--fail_stack.avail];
  14979. X    }
  14980. X
  14981. X      /* We should never be about to go beyond the end of the pattern.  */
  14982. X      assert (p < pend);
  14983. X      
  14984. X#ifdef SWITCH_ENUM_BUG
  14985. X      switch ((int) ((re_opcode_t) *p++))
  14986. X#else
  14987. X      switch ((re_opcode_t) *p++)
  14988. X#endif
  14989. X    {
  14990. X
  14991. X        /* I guess the idea here is to simply not bother with a fastmap
  14992. X           if a backreference is used, since it's too hard to figure out
  14993. X           the fastmap for the corresponding group.  Setting
  14994. X           `can_be_null' stops `re_search_2' from using the fastmap, so
  14995. X           that is all we do.  */
  14996. X    case duplicate:
  14997. X      bufp->can_be_null = 1;
  14998. X          return 0;
  14999. X
  15000. X
  15001. X      /* Following are the cases which match a character.  These end
  15002. X         with `break'.  */
  15003. X
  15004. X    case exactn:
  15005. X          fastmap[p[1]] = 1;
  15006. X      break;
  15007. X
  15008. X
  15009. X        case charset:
  15010. X          for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
  15011. X        if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
  15012. X              fastmap[j] = 1;
  15013. X      break;
  15014. X
  15015. X
  15016. X    case charset_not:
  15017. X      /* Chars beyond end of map must be allowed.  */
  15018. X      for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
  15019. X            fastmap[j] = 1;
  15020. X
  15021. X      for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
  15022. X        if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
  15023. X              fastmap[j] = 1;
  15024. X          break;
  15025. X
  15026. X
  15027. X    case wordchar:
  15028. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  15029. X        if (SYNTAX (j) == Sword)
  15030. X          fastmap[j] = 1;
  15031. X      break;
  15032. X
  15033. X
  15034. X    case notwordchar:
  15035. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  15036. X        if (SYNTAX (j) != Sword)
  15037. X          fastmap[j] = 1;
  15038. X      break;
  15039. X
  15040. X
  15041. X        case anychar:
  15042. X          /* `.' matches anything ...  */
  15043. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  15044. X            fastmap[j] = 1;
  15045. X
  15046. X          /* ... except perhaps newline.  */
  15047. X          if (!(bufp->syntax & RE_DOT_NEWLINE))
  15048. X            fastmap['\n'] = 0;
  15049. X
  15050. X          /* Return if we have already set `can_be_null'; if we have,
  15051. X             then the fastmap is irrelevant.  Something's wrong here.  */
  15052. X      else if (bufp->can_be_null)
  15053. X        return 0;
  15054. X
  15055. X          /* Otherwise, have to check alternative paths.  */
  15056. X      break;
  15057. X
  15058. X
  15059. X#ifdef emacs
  15060. X        case syntaxspec:
  15061. X      k = *p++;
  15062. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  15063. X        if (SYNTAX (j) == (enum syntaxcode) k)
  15064. X          fastmap[j] = 1;
  15065. X      break;
  15066. X
  15067. X
  15068. X    case notsyntaxspec:
  15069. X      k = *p++;
  15070. X      for (j = 0; j < (1 << BYTEWIDTH); j++)
  15071. X        if (SYNTAX (j) != (enum syntaxcode) k)
  15072. X          fastmap[j] = 1;
  15073. X      break;
  15074. X
  15075. X
  15076. X      /* All cases after this match the empty string.  These end with
  15077. X         `continue'.  */
  15078. X
  15079. X
  15080. X    case before_dot:
  15081. X    case at_dot:
  15082. X    case after_dot:
  15083. X          continue;
  15084. X#endif /* not emacs */
  15085. X
  15086. X
  15087. X        case no_op:
  15088. X        case begline:
  15089. X        case endline:
  15090. X    case begbuf:
  15091. X    case endbuf:
  15092. X    case wordbound:
  15093. X    case notwordbound:
  15094. X    case wordbeg:
  15095. X    case wordend:
  15096. X        case push_dummy_failure:
  15097. X          continue;
  15098. X
  15099. X
  15100. X    case jump_n:
  15101. X        case pop_failure_jump:
  15102. X    case maybe_pop_jump:
  15103. X    case jump:
  15104. X        case jump_past_alt:
  15105. X    case dummy_failure_jump:
  15106. X          EXTRACT_NUMBER_AND_INCR (j, p);
  15107. X      p += j;    
  15108. X      if (j > 0)
  15109. X        continue;
  15110. X            
  15111. X          /* Jump backward implies we just went through the body of a
  15112. X             loop and matched nothing.  Opcode jumped to should be
  15113. X             `on_failure_jump' or `succeed_n'.  Just treat it like an
  15114. X             ordinary jump.  For a * loop, it has pushed its failure
  15115. X             point already; if so, discard that as redundant.  */
  15116. X          if ((re_opcode_t) *p != on_failure_jump
  15117. X          && (re_opcode_t) *p != succeed_n)
  15118. X        continue;
  15119. X
  15120. X          p++;
  15121. X          EXTRACT_NUMBER_AND_INCR (j, p);
  15122. X          p += j;        
  15123. X      
  15124. X          /* If what's on the stack is where we are now, pop it.  */
  15125. X          if (!FAIL_STACK_EMPTY () 
  15126. X          && fail_stack.stack[fail_stack.avail - 1] == p)
  15127. X            fail_stack.avail--;
  15128. X
  15129. X          continue;
  15130. X
  15131. X
  15132. X        case on_failure_jump:
  15133. X        case on_failure_keep_string_jump:
  15134. X    handle_on_failure_jump:
  15135. X          EXTRACT_NUMBER_AND_INCR (j, p);
  15136. X
  15137. X          /* For some patterns, e.g., `(a?)?', `p+j' here points to the
  15138. X             end of the pattern.  We don't want to push such a point,
  15139. X             since when we restore it above, entering the switch will
  15140. X             increment `p' past the end of the pattern.  We don't need
  15141. X             to push such a point since we obviously won't find any more
  15142. X             fastmap entries beyond `pend'.  Such a pattern can match
  15143. X             the null string, though.  */
  15144. X          if (p + j < pend)
  15145. X            {
  15146. X              if (!PUSH_PATTERN_OP (p + j, fail_stack))
  15147. X                return -2;
  15148. X            }
  15149. X          else
  15150. X            bufp->can_be_null = 1;
  15151. X
  15152. X          if (succeed_n_p)
  15153. X            {
  15154. X              EXTRACT_NUMBER_AND_INCR (k, p);    /* Skip the n.  */
  15155. X              succeed_n_p = false;
  15156. X        }
  15157. X
  15158. X          continue;
  15159. X
  15160. X
  15161. X    case succeed_n:
  15162. X          /* Get to the number of times to succeed.  */
  15163. X          p += 2;        
  15164. X
  15165. X          /* Increment p past the n for when k != 0.  */
  15166. X          EXTRACT_NUMBER_AND_INCR (k, p);
  15167. X          if (k == 0)
  15168. X        {
  15169. X              p -= 4;
  15170. X            succeed_n_p = true;  /* Spaghetti code alert.  */
  15171. X              goto handle_on_failure_jump;
  15172. X            }
  15173. X          continue;
  15174. X
  15175. X
  15176. X    case set_number_at:
  15177. X          p += 4;
  15178. X          continue;
  15179. X
  15180. X
  15181. X    case start_memory:
  15182. X        case stop_memory:
  15183. X      p += 2;
  15184. X      continue;
  15185. X
  15186. X
  15187. X    default:
  15188. X          abort (); /* We have listed all the cases.  */
  15189. X        } /* switch *p++ */
  15190. X
  15191. X      /* Getting here means we have found the possible starting
  15192. X         characters for one path of the pattern -- and that the empty
  15193. X         string does not match.  We need not follow this path further.
  15194. X         Instead, look at the next alternative (remembered on the
  15195. X         stack), or quit if no more.  The test at the top of the loop
  15196. X         does these things.  */
  15197. X      path_can_be_null = false;
  15198. X      p = pend;
  15199. X    } /* while p */
  15200. X
  15201. X  /* Set `can_be_null' for the last path (also the first path, if the
  15202. X     pattern is empty).  */
  15203. X  bufp->can_be_null |= path_can_be_null;
  15204. X  return 0;
  15205. X} /* re_compile_fastmap */
  15206. X
  15207. X/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
  15208. X   ENDS.  Subsequent matches using PATTERN_BUFFER and REGS will use
  15209. X   this memory for recording register information.  STARTS and ENDS
  15210. X   must be allocated using the malloc library routine, and must each
  15211. X   be at least NUM_REGS * sizeof (regoff_t) bytes long.
  15212. X
  15213. X   If NUM_REGS == 0, then subsequent matches should allocate their own
  15214. X   register data.
  15215. X
  15216. X   Unless this function is called, the first search or match using
  15217. X   PATTERN_BUFFER will allocate its own register data, without
  15218. X   freeing the old data.  */
  15219. X
  15220. Xvoid
  15221. Xre_set_registers (bufp, regs, num_regs, starts, ends)
  15222. X    struct re_pattern_buffer *bufp;
  15223. X    struct re_registers *regs;
  15224. X    unsigned num_regs;
  15225. X    regoff_t *starts, *ends;
  15226. X{
  15227. X  if (num_regs)
  15228. X    {
  15229. X      bufp->regs_allocated = REGS_REALLOCATE;
  15230. X      regs->num_regs = num_regs;
  15231. X      regs->start = starts;
  15232. X      regs->end = ends;
  15233. X    }
  15234. X  else
  15235. X    {
  15236. X      bufp->regs_allocated = REGS_UNALLOCATED;
  15237. X      regs->num_regs = 0;
  15238. X      regs->start = regs->end = (regoff_t) 0;
  15239. X    }
  15240. X}
  15241. X
  15242. X/* Searching routines.  */
  15243. X
  15244. X/* Like re_search_2, below, but only one string is specified, and
  15245. X   doesn't let you say where to stop matching. */
  15246. X
  15247. Xint
  15248. Xre_search (bufp, string, size, startpos, range, regs)
  15249. X     struct re_pattern_buffer *bufp;
  15250. X     const char *string;
  15251. X     int size, startpos, range;
  15252. X     struct re_registers *regs;
  15253. X{
  15254. X  return re_search_2 (bufp, NULL, 0, string, size, startpos, range, 
  15255. X              regs, size);
  15256. X}
  15257. X
  15258. X
  15259. X/* Using the compiled pattern in BUFP->buffer, first tries to match the
  15260. X   virtual concatenation of STRING1 and STRING2, starting first at index
  15261. X   STARTPOS, then at STARTPOS + 1, and so on.
  15262. X   
  15263. X   STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
  15264. X   
  15265. X   RANGE is how far to scan while trying to match.  RANGE = 0 means try
  15266. X   only at STARTPOS; in general, the last start tried is STARTPOS +
  15267. X   RANGE.
  15268. X   
  15269. X   In REGS, return the indices of the virtual concatenation of STRING1
  15270. X   and STRING2 that matched the entire BUFP->buffer and its contained
  15271. X   subexpressions.
  15272. X   
  15273. X   Do not consider matching one past the index STOP in the virtual
  15274. X   concatenation of STRING1 and STRING2.
  15275. X
  15276. X   We return either the position in the strings at which the match was
  15277. X   found, -1 if no match, or -2 if error (such as failure
  15278. X   stack overflow).  */
  15279. X
  15280. Xint
  15281. Xre_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
  15282. X     struct re_pattern_buffer *bufp;
  15283. X     const char *string1, *string2;
  15284. X     int size1, size2;
  15285. X     int startpos;
  15286. X     int range;
  15287. X     struct re_registers *regs;
  15288. X     int stop;
  15289. X{
  15290. X  int val;
  15291. X  register char *fastmap = bufp->fastmap;
  15292. X  register char *translate = bufp->translate;
  15293. X  int total_size = size1 + size2;
  15294. X  int endpos = startpos + range;
  15295. X
  15296. X  /* Check for out-of-range STARTPOS.  */
  15297. X  if (startpos < 0 || startpos > total_size)
  15298. X    return -1;
  15299. X    
  15300. X  /* Fix up RANGE if it might eventually take us outside
  15301. X     the virtual concatenation of STRING1 and STRING2.  */
  15302. X  if (endpos < -1)
  15303. X    range = -1 - startpos;
  15304. X  else if (endpos > total_size)
  15305. X    range = total_size - startpos;
  15306. X
  15307. X  /* If the search isn't to be a backwards one, don't waste time in a
  15308. X     search for a pattern that must be anchored.  */
  15309. X  if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
  15310. X    {
  15311. X      if (startpos > 0)
  15312. X    return -1;
  15313. X      else
  15314. X    range = 1;
  15315. X    }
  15316. X
  15317. X  /* Update the fastmap now if not correct already.  */
  15318. X  if (fastmap && !bufp->fastmap_accurate)
  15319. X    if (re_compile_fastmap (bufp) == -2)
  15320. X      return -2;
  15321. X  
  15322. X  /* Loop through the string, looking for a place to start matching.  */
  15323. X  for (;;)
  15324. X    { 
  15325. X      /* If a fastmap is supplied, skip quickly over characters that
  15326. X         cannot be the start of a match.  If the pattern can match the
  15327. X         null string, however, we don't need to skip characters; we want
  15328. X         the first null string.  */
  15329. X      if (fastmap && startpos < total_size && !bufp->can_be_null)
  15330. X    {
  15331. X      if (range > 0)    /* Searching forwards.  */
  15332. X        {
  15333. X          register const char *d;
  15334. X          register int lim = 0;
  15335. X          int irange = range;
  15336. X
  15337. X              if (startpos < size1 && startpos + range >= size1)
  15338. X                lim = range - (size1 - startpos);
  15339. X
  15340. X          d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
  15341. X   
  15342. X              /* Written out as an if-else to avoid testing `translate'
  15343. X                 inside the loop.  */
  15344. X          if (translate)
  15345. X                while (range > lim
  15346. X                       && !fastmap[(unsigned char)
  15347. X                   translate[(unsigned char) *d++]])
  15348. X                  range--;
  15349. X          else
  15350. X                while (range > lim && !fastmap[(unsigned char) *d++])
  15351. X                  range--;
  15352. X
  15353. X          startpos += irange - range;
  15354. X        }
  15355. X      else                /* Searching backwards.  */
  15356. X        {
  15357. X          register char c = (size1 == 0 || startpos >= size1
  15358. X                                 ? string2[startpos - size1] 
  15359. X                                 : string1[startpos]);
  15360. X
  15361. X          if (!fastmap[(unsigned char) TRANSLATE (c)])
  15362. X        goto advance;
  15363. X        }
  15364. X    }
  15365. X
  15366. X      /* If can't match the null string, and that's all we have left, fail.  */
  15367. X      if (range >= 0 && startpos == total_size && fastmap
  15368. X          && !bufp->can_be_null)
  15369. X    return -1;
  15370. X
  15371. X      val = re_match_2 (bufp, string1, size1, string2, size2,
  15372. X                    startpos, regs, stop);
  15373. X      if (val >= 0)
  15374. X    return startpos;
  15375. X        
  15376. X      if (val == -2)
  15377. X    return -2;
  15378. X
  15379. X    advance:
  15380. X      if (!range) 
  15381. X        break;
  15382. X      else if (range > 0) 
  15383. X        {
  15384. X          range--; 
  15385. X          startpos++;
  15386. X        }
  15387. X      else
  15388. X        {
  15389. X          range++; 
  15390. X          startpos--;
  15391. X        }
  15392. X    }
  15393. X  return -1;
  15394. X} /* re_search_2 */
  15395. X
  15396. X/* Declarations and macros for re_match_2.  */
  15397. X
  15398. Xstatic int bcmp_translate ();
  15399. Xstatic boolean alt_match_null_string_p (),
  15400. X               common_op_match_null_string_p (),
  15401. X               group_match_null_string_p ();
  15402. X
  15403. X/* Structure for per-register (a.k.a. per-group) information.
  15404. X   This must not be longer than one word, because we push this value
  15405. X   onto the failure stack.  Other register information, such as the
  15406. X   starting and ending positions (which are addresses), and the list of
  15407. X   inner groups (which is a bits list) are maintained in separate
  15408. X   variables.  
  15409. X   
  15410. X   We are making a (strictly speaking) nonportable assumption here: that
  15411. X   the compiler will pack our bit fields into something that fits into
  15412. X   the type of `word', i.e., is something that fits into one item on the
  15413. X   failure stack.  */
  15414. Xtypedef union
  15415. X{
  15416. X  fail_stack_elt_t word;
  15417. X  struct
  15418. X  {
  15419. X      /* This field is one if this group can match the empty string,
  15420. X         zero if not.  If not yet determined,  `MATCH_NULL_UNSET_VALUE'.  */
  15421. X#define MATCH_NULL_UNSET_VALUE 3
  15422. X    unsigned match_null_string_p : 2;
  15423. X    unsigned is_active : 1;
  15424. X    unsigned matched_something : 1;
  15425. X    unsigned ever_matched_something : 1;
  15426. X  } bits;
  15427. X} register_info_type;
  15428. X
  15429. X#define REG_MATCH_NULL_STRING_P(R)  ((R).bits.match_null_string_p)
  15430. X#define IS_ACTIVE(R)  ((R).bits.is_active)
  15431. X#define MATCHED_SOMETHING(R)  ((R).bits.matched_something)
  15432. X#define EVER_MATCHED_SOMETHING(R)  ((R).bits.ever_matched_something)
  15433. X
  15434. X
  15435. X/* Call this when have matched a real character; it sets `matched' flags
  15436. X   for the subexpressions which we are currently inside.  Also records
  15437. X   that those subexprs have matched.  */
  15438. X#define SET_REGS_MATCHED()                        \
  15439. X  do                                    \
  15440. X    {                                    \
  15441. X      unsigned r;                            \
  15442. X      for (r = lowest_active_reg; r <= highest_active_reg; r++)        \
  15443. X        {                                \
  15444. X          MATCHED_SOMETHING (reg_info[r])                \
  15445. X            = EVER_MATCHED_SOMETHING (reg_info[r])            \
  15446. X            = 1;                            \
  15447. X        }                                \
  15448. X    }                                    \
  15449. X  while (0)
  15450. X
  15451. X
  15452. X/* This converts PTR, a pointer into one of the search strings `string1'
  15453. X   and `string2' into an offset from the beginning of that string.  */
  15454. X#define POINTER_TO_OFFSET(ptr)                        \
  15455. X  (FIRST_STRING_P (ptr) ? (ptr) - string1 : (ptr) - string2 + size1)
  15456. X
  15457. X/* Registers are set to a sentinel when they haven't yet matched.  */
  15458. X#define REG_UNSET_VALUE ((char *) -1)
  15459. X#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
  15460. X
  15461. X
  15462. X/* Macros for dealing with the split strings in re_match_2.  */
  15463. X
  15464. X#define MATCHING_IN_FIRST_STRING  (dend == end_match_1)
  15465. X
  15466. X/* Call before fetching a character with *d.  This switches over to
  15467. X   string2 if necessary.  */
  15468. X#define PREFETCH()                            \
  15469. X  while (d == dend)                                \
  15470. X    {                                    \
  15471. X      /* End of string2 => fail.  */                    \
  15472. X      if (dend == end_match_2)                         \
  15473. X        goto fail;                            \
  15474. X      /* End of string1 => advance to string2.  */             \
  15475. X      d = string2;                                \
  15476. X      dend = end_match_2;                        \
  15477. X    }
  15478. X
  15479. X
  15480. X/* Test if at very beginning or at very end of the virtual concatenation
  15481. X   of `string1' and `string2'.  If only one string, it's `string2'.  */
  15482. X#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
  15483. X#define AT_STRINGS_END(d) ((d) == end2)    
  15484. X
  15485. X
  15486. X/* Test if D points to a character which is word-constituent.  We have
  15487. X   two special cases to check for: if past the end of string1, look at
  15488. X   the first character in string2; and if before the beginning of
  15489. X   string2, look at the last character in string1.  */
  15490. X#define WORDCHAR_P(d)                            \
  15491. X  (SYNTAX ((d) == end1 ? *string2                    \
  15492. X           : (d) == string2 - 1 ? *(end1 - 1) : *(d))            \
  15493. X   == Sword)
  15494. X
  15495. X/* Test if the character before D and the one at D differ with respect
  15496. X   to being word-constituent.  */
  15497. X#define AT_WORD_BOUNDARY(d)                        \
  15498. X  (AT_STRINGS_BEG (d) || AT_STRINGS_END (d)                \
  15499. X   || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
  15500. X
  15501. X
  15502. X/* Free everything we malloc.  */
  15503. X#ifdef REGEX_MALLOC
  15504. X#define FREE_VAR(var) if (var) free (var); var = NULL
  15505. X#define FREE_VARIABLES()                        \
  15506. X  do {                                    \
  15507. X    FREE_VAR (fail_stack.stack);                    \
  15508. X    FREE_VAR (regstart);                        \
  15509. X    FREE_VAR (regend);                            \
  15510. X    FREE_VAR (old_regstart);                        \
  15511. X    FREE_VAR (old_regend);                        \
  15512. X    FREE_VAR (best_regstart);                        \
  15513. X    FREE_VAR (best_regend);                        \
  15514. X    FREE_VAR (reg_info);                        \
  15515. X    FREE_VAR (reg_dummy);                        \
  15516. X    FREE_VAR (reg_info_dummy);                        \
  15517. X  } while (0)
  15518. X#else /* not REGEX_MALLOC */
  15519. X/* Some MIPS systems (at least) want this to free alloca'd storage.  */
  15520. X#define FREE_VARIABLES() alloca (0)
  15521. X#endif /* not REGEX_MALLOC */
  15522. X
  15523. X
  15524. X/* These values must meet several constraints.  They must not be valid
  15525. X   register values; since we have a limit of 255 registers (because
  15526. X   we use only one byte in the pattern for the register number), we can
  15527. X   use numbers larger than 255.  They must differ by 1, because of
  15528. X   NUM_FAILURE_ITEMS above.  And the value for the lowest register must
  15529. X   be larger than the value for the highest register, so we do not try
  15530. X   to actually save any registers when none are active.  */
  15531. X#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
  15532. X#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
  15533. X
  15534. X/* Matching routines.  */
  15535. X
  15536. X#ifndef emacs   /* Emacs never uses this.  */
  15537. X/* re_match is like re_match_2 except it takes only a single string.  */
  15538. X
  15539. Xint
  15540. Xre_match (bufp, string, size, pos, regs)
  15541. X     struct re_pattern_buffer *bufp;
  15542. X     const char *string;
  15543. X     int size, pos;
  15544. X     struct re_registers *regs;
  15545. X {
  15546. X  return re_match_2 (bufp, NULL, 0, string, size, pos, regs, size); 
  15547. X}
  15548. X#endif /* not emacs */
  15549. X
  15550. X
  15551. X/* re_match_2 matches the compiled pattern in BUFP against the
  15552. X   the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
  15553. X   and SIZE2, respectively).  We start matching at POS, and stop
  15554. X   matching at STOP.
  15555. X   
  15556. X   If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
  15557. X   store offsets for the substring each group matched in REGS.  See the
  15558. X   documentation for exactly how many groups we fill.
  15559. X
  15560. X   We return -1 if no match, -2 if an internal error (such as the
  15561. X   failure stack overflowing).  Otherwise, we return the length of the
  15562. X   matched substring.  */
  15563. X
  15564. Xint
  15565. Xre_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
  15566. X     struct re_pattern_buffer *bufp;
  15567. X     const char *string1, *string2;
  15568. X     int size1, size2;
  15569. X     int pos;
  15570. X     struct re_registers *regs;
  15571. X     int stop;
  15572. X{
  15573. X  /* General temporaries.  */
  15574. X  int mcnt;
  15575. X  unsigned char *p1;
  15576. X
  15577. X  /* Just past the end of the corresponding string.  */
  15578. X  const char *end1, *end2;
  15579. X
  15580. X  /* Pointers into string1 and string2, just past the last characters in
  15581. X     each to consider matching.  */
  15582. X  const char *end_match_1, *end_match_2;
  15583. X
  15584. X  /* Where we are in the data, and the end of the current string.  */
  15585. X  const char *d, *dend;
  15586. X  
  15587. X  /* Where we are in the pattern, and the end of the pattern.  */
  15588. X  unsigned char *p = bufp->buffer;
  15589. X  register unsigned char *pend = p + bufp->used;
  15590. X
  15591. X  /* We use this to map every character in the string.  */
  15592. X  char *translate = bufp->translate;
  15593. X
  15594. X  /* Failure point stack.  Each place that can handle a failure further
  15595. X     down the line pushes a failure point on this stack.  It consists of
  15596. X     restart, regend, and reg_info for all registers corresponding to
  15597. X     the subexpressions we're currently inside, plus the number of such
  15598. X     registers, and, finally, two char *'s.  The first char * is where
  15599. X     to resume scanning the pattern; the second one is where to resume
  15600. X     scanning the strings.  If the latter is zero, the failure point is
  15601. X     a ``dummy''; if a failure happens and the failure point is a dummy,
  15602. X     it gets discarded and the next next one is tried.  */
  15603. X  fail_stack_type fail_stack;
  15604. X#ifdef DEBUG
  15605. X  static unsigned failure_id = 0;
  15606. X  unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
  15607. X#endif
  15608. X
  15609. X  /* We fill all the registers internally, independent of what we
  15610. X     return, for use in backreferences.  The number here includes
  15611. X     an element for register zero.  */
  15612. X  unsigned num_regs = bufp->re_nsub + 1;
  15613. X  
  15614. X  /* The currently active registers.  */
  15615. X  unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
  15616. X  unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
  15617. X
  15618. X  /* Information on the contents of registers. These are pointers into
  15619. X     the input strings; they record just what was matched (on this
  15620. X     attempt) by a subexpression part of the pattern, that is, the
  15621. X     regnum-th regstart pointer points to where in the pattern we began
  15622. X     matching and the regnum-th regend points to right after where we
  15623. X     stopped matching the regnum-th subexpression.  (The zeroth register
  15624. X     keeps track of what the whole pattern matches.)  */
  15625. X  const char **regstart, **regend;
  15626. X
  15627. X  /* If a group that's operated upon by a repetition operator fails to
  15628. X     match anything, then the register for its start will need to be
  15629. X     restored because it will have been set to wherever in the string we
  15630. X     are when we last see its open-group operator.  Similarly for a
  15631. X     register's end.  */
  15632. X  const char **old_regstart, **old_regend;
  15633. X
  15634. X  /* The is_active field of reg_info helps us keep track of which (possibly
  15635. X     nested) subexpressions we are currently in. The matched_something
  15636. X     field of reg_info[reg_num] helps us tell whether or not we have
  15637. X     matched any of the pattern so far this time through the reg_num-th
  15638. X     subexpression.  These two fields get reset each time through any
  15639. X     loop their register is in.  */
  15640. X  register_info_type *reg_info; 
  15641. X
  15642. X  /* The following record the register info as found in the above
  15643. X     variables when we find a match better than any we've seen before. 
  15644. X     This happens as we backtrack through the failure points, which in
  15645. X     turn happens only if we have not yet matched the entire string. */
  15646. X  unsigned best_regs_set = false;
  15647. X  const char **best_regstart, **best_regend;
  15648. X  
  15649. X  /* Logically, this is `best_regend[0]'.  But we don't want to have to
  15650. X     allocate space for that if we're not allocating space for anything
  15651. X     else (see below).  Also, we never need info about register 0 for
  15652. X     any of the other register vectors, and it seems rather a kludge to
  15653. X     treat `best_regend' differently than the rest.  So we keep track of
  15654. X     the end of the best match so far in a separate variable.  We
  15655. X     initialize this to NULL so that when we backtrack the first time
  15656. X     and need to test it, it's not garbage.  */
  15657. X  const char *match_end = NULL;
  15658. X
  15659. X  /* Used when we pop values we don't care about.  */
  15660. X  const char **reg_dummy;
  15661. X  register_info_type *reg_info_dummy;
  15662. X
  15663. X#ifdef DEBUG
  15664. X  /* Counts the total number of registers pushed.  */
  15665. X  unsigned num_regs_pushed = 0;     
  15666. X#endif
  15667. X
  15668. X  DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
  15669. X  
  15670. X  INIT_FAIL_STACK ();
  15671. X  
  15672. X  /* Do not bother to initialize all the register variables if there are
  15673. X     no groups in the pattern, as it takes a fair amount of time.  If
  15674. X     there are groups, we include space for register 0 (the whole
  15675. X     pattern), even though we never use it, since it simplifies the
  15676. X     array indexing.  We should fix this.  */
  15677. X  if (bufp->re_nsub)
  15678. X    {
  15679. X      regstart = REGEX_TALLOC (num_regs, const char *);
  15680. X      regend = REGEX_TALLOC (num_regs, const char *);
  15681. X      old_regstart = REGEX_TALLOC (num_regs, const char *);
  15682. X      old_regend = REGEX_TALLOC (num_regs, const char *);
  15683. X      best_regstart = REGEX_TALLOC (num_regs, const char *);
  15684. X      best_regend = REGEX_TALLOC (num_regs, const char *);
  15685. X      reg_info = REGEX_TALLOC (num_regs, register_info_type);
  15686. X      reg_dummy = REGEX_TALLOC (num_regs, const char *);
  15687. X      reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
  15688. X
  15689. X      if (!(regstart && regend && old_regstart && old_regend && reg_info 
  15690. X            && best_regstart && best_regend && reg_dummy && reg_info_dummy)) 
  15691. X        {
  15692. X          FREE_VARIABLES ();
  15693. X          return -2;
  15694. X        }
  15695. X    }
  15696. X#ifdef REGEX_MALLOC
  15697. X  else
  15698. X    {
  15699. X      /* We must initialize all our variables to NULL, so that
  15700. X         `FREE_VARIABLES' doesn't try to free them.  */
  15701. X      regstart = regend = old_regstart = old_regend = best_regstart
  15702. X        = best_regend = reg_dummy = NULL;
  15703. X      reg_info = reg_info_dummy = (register_info_type *) NULL;
  15704. X    }
  15705. X#endif /* REGEX_MALLOC */
  15706. X
  15707. X  /* The starting position is bogus.  */
  15708. X  if (pos < 0 || pos > size1 + size2)
  15709. X    {
  15710. X      FREE_VARIABLES ();
  15711. X      return -1;
  15712. X    }
  15713. X    
  15714. X  /* Initialize subexpression text positions to -1 to mark ones that no
  15715. X     start_memory/stop_memory has been seen for. Also initialize the
  15716. X     register information struct.  */
  15717. X  for (mcnt = 1; mcnt < num_regs; mcnt++)
  15718. X    {
  15719. X      regstart[mcnt] = regend[mcnt] 
  15720. X        = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
  15721. X        
  15722. X      REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
  15723. X      IS_ACTIVE (reg_info[mcnt]) = 0;
  15724. X      MATCHED_SOMETHING (reg_info[mcnt]) = 0;
  15725. X      EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
  15726. X    }
  15727. X  
  15728. X  /* We move `string1' into `string2' if the latter's empty -- but not if
  15729. X     `string1' is null.  */
  15730. X  if (size2 == 0 && string1 != NULL)
  15731. X    {
  15732. X      string2 = string1;
  15733. X      size2 = size1;
  15734. X      string1 = 0;
  15735. X      size1 = 0;
  15736. X    }
  15737. X  end1 = string1 + size1;
  15738. X  end2 = string2 + size2;
  15739. X
  15740. X  /* Compute where to stop matching, within the two strings.  */
  15741. X  if (stop <= size1)
  15742. X    {
  15743. X      end_match_1 = string1 + stop;
  15744. X      end_match_2 = string2;
  15745. X    }
  15746. X  else
  15747. X    {
  15748. X      end_match_1 = end1;
  15749. X      end_match_2 = string2 + stop - size1;
  15750. X    }
  15751. X
  15752. X  /* `p' scans through the pattern as `d' scans through the data. 
  15753. X     `dend' is the end of the input string that `d' points within.  `d'
  15754. X     is advanced into the following input string whenever necessary, but
  15755. X     this happens before fetching; therefore, at the beginning of the
  15756. X     loop, `d' can be pointing at the end of a string, but it cannot
  15757. X     equal `string2'.  */
  15758. X  if (size1 > 0 && pos <= size1)
  15759. X    {
  15760. X      d = string1 + pos;
  15761. X      dend = end_match_1;
  15762. X    }
  15763. X  else
  15764. X    {
  15765. X      d = string2 + pos - size1;
  15766. X      dend = end_match_2;
  15767. X    }
  15768. X
  15769. X  DEBUG_PRINT1 ("The compiled pattern is: ");
  15770. X  DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
  15771. X  DEBUG_PRINT1 ("The string to match is: `");
  15772. X  DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
  15773. X  DEBUG_PRINT1 ("'\n");
  15774. X  
  15775. X  /* This loops over pattern commands.  It exits by returning from the
  15776. X     function if the match is complete, or it drops through if the match
  15777. X     fails at this starting point in the input data.  */
  15778. X  for (;;)
  15779. X    {
  15780. X      DEBUG_PRINT2 ("\n0x%x: ", p);
  15781. X
  15782. X      if (p == pend)
  15783. X    { /* End of pattern means we might have succeeded.  */
  15784. X          DEBUG_PRINT1 ("end of pattern ... ");
  15785. X          
  15786. X      /* If we haven't matched the entire string, and we want the
  15787. X             longest match, try backtracking.  */
  15788. X          if (d != end_match_2)
  15789. X        {
  15790. X              DEBUG_PRINT1 ("backtracking.\n");
  15791. X              
  15792. X              if (!FAIL_STACK_EMPTY ())
  15793. X                { /* More failure points to try.  */
  15794. X                  boolean same_str_p = (FIRST_STRING_P (match_end) 
  15795. X                                == MATCHING_IN_FIRST_STRING);
  15796. X
  15797. X                  /* If exceeds best match so far, save it.  */
  15798. X                  if (!best_regs_set
  15799. X                      || (same_str_p && d > match_end)
  15800. X                      || (!same_str_p && !MATCHING_IN_FIRST_STRING))
  15801. X                    {
  15802. X                      best_regs_set = true;
  15803. X                      match_end = d;
  15804. X                      
  15805. X                      DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
  15806. X                      
  15807. X                      for (mcnt = 1; mcnt < num_regs; mcnt++)
  15808. X                        {
  15809. X                          best_regstart[mcnt] = regstart[mcnt];
  15810. X                          best_regend[mcnt] = regend[mcnt];
  15811. X                        }
  15812. X                    }
  15813. X                  goto fail;           
  15814. X                }
  15815. X
  15816. X              /* If no failure points, don't restore garbage.  */
  15817. X              else if (best_regs_set)   
  15818. X                {
  15819. X              restore_best_regs:
  15820. X                  /* Restore best match.  It may happen that `dend ==
  15821. X                     end_match_1' while the restored d is in string2.
  15822. X                     For example, the pattern `x.*y.*z' against the
  15823. X                     strings `x-' and `y-z-', if the two strings are
  15824. X                     not consecutive in memory.  */
  15825. X                  DEBUG_PRINT1 ("Restoring best registers.\n");
  15826. X                  
  15827. X                  d = match_end;
  15828. X                  dend = ((d >= string1 && d <= end1)
  15829. X                   ? end_match_1 : end_match_2);
  15830. X
  15831. X          for (mcnt = 1; mcnt < num_regs; mcnt++)
  15832. X            {
  15833. X              regstart[mcnt] = best_regstart[mcnt];
  15834. X              regend[mcnt] = best_regend[mcnt];
  15835. X            }
  15836. X                }
  15837. X            } /* d != end_match_2 */
  15838. X
  15839. X          DEBUG_PRINT1 ("Accepting match.\n");
  15840. X
  15841. X          /* If caller wants register contents data back, do it.  */
  15842. X          if (regs && !bufp->no_sub)
  15843. X        {
  15844. X              /* Have the register data arrays been allocated?  */
  15845. X              if (bufp->regs_allocated == REGS_UNALLOCATED)
  15846. X                { /* No.  So allocate them with malloc.  We need one
  15847. X                     extra element beyond `num_regs' for the `-1' marker
  15848. X                     GNU code uses.  */
  15849. X                  regs->num_regs = MAX (RE_NREGS, num_regs + 1);
  15850. X                  regs->start = TALLOC (regs->num_regs, regoff_t);
  15851. X                  regs->end = TALLOC (regs->num_regs, regoff_t);
  15852. X                  if (regs->start == NULL || regs->end == NULL)
  15853. X                    return -2;
  15854. X                  bufp->regs_allocated = REGS_REALLOCATE;
  15855. X                }
  15856. X              else if (bufp->regs_allocated == REGS_REALLOCATE)
  15857. X                { /* Yes.  If we need more elements than were already
  15858. X                     allocated, reallocate them.  If we need fewer, just
  15859. X                     leave it alone.  */
  15860. X                  if (regs->num_regs < num_regs + 1)
  15861. X                    {
  15862. X                      regs->num_regs = num_regs + 1;
  15863. X                      RETALLOC (regs->start, regs->num_regs, regoff_t);
  15864. X                      RETALLOC (regs->end, regs->num_regs, regoff_t);
  15865. X                      if (regs->start == NULL || regs->end == NULL)
  15866. X                        return -2;
  15867. X                    }
  15868. X                }
  15869. X              else
  15870. X                assert (bufp->regs_allocated == REGS_FIXED);
  15871. X
  15872. X              /* Convert the pointer data in `regstart' and `regend' to
  15873. X                 indices.  Register zero has to be set differently,
  15874. X                 since we haven't kept track of any info for it.  */
  15875. X              if (regs->num_regs > 0)
  15876. X                {
  15877. X                  regs->start[0] = pos;
  15878. X                  regs->end[0] = (MATCHING_IN_FIRST_STRING ? d - string1
  15879. X                      : d - string2 + size1);
  15880. X                }
  15881. X              
  15882. X              /* Go through the first `min (num_regs, regs->num_regs)'
  15883. X                 registers, since that is all we initialized.  */
  15884. X          for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
  15885. X        {
  15886. X                  if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
  15887. X                    regs->start[mcnt] = regs->end[mcnt] = -1;
  15888. X                  else
  15889. X                    {
  15890. X              regs->start[mcnt] = POINTER_TO_OFFSET (regstart[mcnt]);
  15891. X                      regs->end[mcnt] = POINTER_TO_OFFSET (regend[mcnt]);
  15892. X                    }
  15893. X        }
  15894. X              
  15895. X              /* If the regs structure we return has more elements than
  15896. X                 were in the pattern, set the extra elements to -1.  If
  15897. X                 we (re)allocated the registers, this is the case,
  15898. X                 because we always allocate enough to have at least one
  15899. X                 -1 at the end.  */
  15900. X              for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
  15901. X                regs->start[mcnt] = regs->end[mcnt] = -1;
  15902. X        } /* regs && !bufp->no_sub */
  15903. X
  15904. X          FREE_VARIABLES ();
  15905. X          DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
  15906. X                        nfailure_points_pushed, nfailure_points_popped,
  15907. X                        nfailure_points_pushed - nfailure_points_popped);
  15908. X          DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
  15909. X
  15910. X          mcnt = d - pos - (MATCHING_IN_FIRST_STRING 
  15911. X                ? string1 
  15912. X                : string2 - size1);
  15913. X
  15914. X          DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
  15915. X
  15916. X          return mcnt;
  15917. X        }
  15918. X
  15919. X      /* Otherwise match next pattern command.  */
  15920. X#ifdef SWITCH_ENUM_BUG
  15921. X      switch ((int) ((re_opcode_t) *p++))
  15922. X#else
  15923. X      switch ((re_opcode_t) *p++)
  15924. X#endif
  15925. X    {
  15926. X        /* Ignore these.  Used to ignore the n of succeed_n's which
  15927. X           currently have n == 0.  */
  15928. X        case no_op:
  15929. X          DEBUG_PRINT1 ("EXECUTING no_op.\n");
  15930. X          break;
  15931. X
  15932. X
  15933. X        /* Match the next n pattern characters exactly.  The following
  15934. X           byte in the pattern defines n, and the n bytes after that
  15935. X           are the characters to match.  */
  15936. X    case exactn:
  15937. X      mcnt = *p++;
  15938. X          DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
  15939. X
  15940. X          /* This is written out as an if-else so we don't waste time
  15941. X             testing `translate' inside the loop.  */
  15942. X          if (translate)
  15943. X        {
  15944. X          do
  15945. X        {
  15946. X          PREFETCH ();
  15947. X          if (translate[(unsigned char) *d++] != (char) *p++)
  15948. X                    goto fail;
  15949. X        }
  15950. X          while (--mcnt);
  15951. X        }
  15952. X      else
  15953. X        {
  15954. X          do
  15955. X        {
  15956. X          PREFETCH ();
  15957. X          if (*d++ != (char) *p++) goto fail;
  15958. X        }
  15959. X          while (--mcnt);
  15960. X        }
  15961. X      SET_REGS_MATCHED ();
  15962. X          break;
  15963. X
  15964. X
  15965. X        /* Match any character except possibly a newline or a null.  */
  15966. X    case anychar:
  15967. X          DEBUG_PRINT1 ("EXECUTING anychar.\n");
  15968. X
  15969. X          PREFETCH ();
  15970. X
  15971. X          if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
  15972. X              || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
  15973. X        goto fail;
  15974. X
  15975. X          SET_REGS_MATCHED ();
  15976. X          DEBUG_PRINT2 ("  Matched `%d'.\n", *d);
  15977. X          d++;
  15978. X      break;
  15979. X
  15980. X
  15981. X    case charset:
  15982. X    case charset_not:
  15983. X      {
  15984. X        register unsigned char c;
  15985. X        boolean not = (re_opcode_t) *(p - 1) == charset_not;
  15986. X
  15987. X            DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
  15988. X
  15989. X        PREFETCH ();
  15990. X        c = TRANSLATE (*d); /* The character to match.  */
  15991. X
  15992. X            /* Cast to `unsigned' instead of `unsigned char' in case the
  15993. X               bit list is a full 32 bytes long.  */
  15994. X        if (c < (unsigned) (*p * BYTEWIDTH)
  15995. X        && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
  15996. X          not = !not;
  15997. X
  15998. X        p += 1 + *p;
  15999. X
  16000. X        if (!not) goto fail;
  16001. X            
  16002. X        SET_REGS_MATCHED ();
  16003. X            d++;
  16004. X        break;
  16005. X      }
  16006. X
  16007. X
  16008. X        /* The beginning of a group is represented by start_memory.
  16009. X           The arguments are the register number in the next byte, and the
  16010. X           number of groups inner to this one in the next.  The text
  16011. X           matched within the group is recorded (in the internal
  16012. X           registers data structure) under the register number.  */
  16013. X        case start_memory:
  16014. X      DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
  16015. X
  16016. X          /* Find out if this group can match the empty string.  */
  16017. X      p1 = p;        /* To send to group_match_null_string_p.  */
  16018. X          
  16019. X          if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
  16020. X            REG_MATCH_NULL_STRING_P (reg_info[*p]) 
  16021. X              = group_match_null_string_p (&p1, pend, reg_info);
  16022. X
  16023. X          /* Save the position in the string where we were the last time
  16024. X             we were at this open-group operator in case the group is
  16025. X             operated upon by a repetition operator, e.g., with `(a*)*b'
  16026. X             against `ab'; then we want to ignore where we are now in
  16027. X             the string in case this attempt to match fails.  */
  16028. X          old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
  16029. X                             ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
  16030. X                             : regstart[*p];
  16031. X      DEBUG_PRINT2 ("  old_regstart: %d\n", 
  16032. X             POINTER_TO_OFFSET (old_regstart[*p]));
  16033. X
  16034. X          regstart[*p] = d;
  16035. X      DEBUG_PRINT2 ("  regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
  16036. X
  16037. X          IS_ACTIVE (reg_info[*p]) = 1;
  16038. X          MATCHED_SOMETHING (reg_info[*p]) = 0;
  16039. X          
  16040. X          /* This is the new highest active register.  */
  16041. X          highest_active_reg = *p;
  16042. X          
  16043. X          /* If nothing was active before, this is the new lowest active
  16044. X             register.  */
  16045. X          if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
  16046. X            lowest_active_reg = *p;
  16047. X
  16048. X          /* Move past the register number and inner group count.  */
  16049. X          p += 2;
  16050. X          break;
  16051. X
  16052. X
  16053. X        /* The stop_memory opcode represents the end of a group.  Its
  16054. X           arguments are the same as start_memory's: the register
  16055. X           number, and the number of inner groups.  */
  16056. X    case stop_memory:
  16057. X      DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
  16058. X             
  16059. X          /* We need to save the string position the last time we were at
  16060. X             this close-group operator in case the group is operated
  16061. X             upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
  16062. X             against `aba'; then we want to ignore where we are now in
  16063. X             the string in case this attempt to match fails.  */
  16064. X          old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
  16065. X                           ? REG_UNSET (regend[*p]) ? d : regend[*p]
  16066. X               : regend[*p];
  16067. X      DEBUG_PRINT2 ("      old_regend: %d\n", 
  16068. X             POINTER_TO_OFFSET (old_regend[*p]));
  16069. X
  16070. X          regend[*p] = d;
  16071. X      DEBUG_PRINT2 ("      regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
  16072. X
  16073. X          /* This register isn't active anymore.  */
  16074. X          IS_ACTIVE (reg_info[*p]) = 0;
  16075. X          
  16076. X          /* If this was the only register active, nothing is active
  16077. X             anymore.  */
  16078. X          if (lowest_active_reg == highest_active_reg)
  16079. X            {
  16080. X              lowest_active_reg = NO_LOWEST_ACTIVE_REG;
  16081. X              highest_active_reg = NO_HIGHEST_ACTIVE_REG;
  16082. X            }
  16083. X          else
  16084. X            { /* We must scan for the new highest active register, since
  16085. X                 it isn't necessarily one less than now: consider
  16086. X                 (a(b)c(d(e)f)g).  When group 3 ends, after the f), the
  16087. X                 new highest active register is 1.  */
  16088. X              unsigned char r = *p - 1;
  16089. X              while (r > 0 && !IS_ACTIVE (reg_info[r]))
  16090. X                r--;
  16091. X              
  16092. X              /* If we end up at register zero, that means that we saved
  16093. X                 the registers as the result of an `on_failure_jump', not
  16094. X                 a `start_memory', and we jumped to past the innermost
  16095. X                 `stop_memory'.  For example, in ((.)*) we save
  16096. X                 registers 1 and 2 as a result of the *, but when we pop
  16097. X                 back to the second ), we are at the stop_memory 1.
  16098. X                 Thus, nothing is active.  */
  16099. X          if (r == 0)
  16100. X                {
  16101. X                  lowest_active_reg = NO_LOWEST_ACTIVE_REG;
  16102. X                  highest_active_reg = NO_HIGHEST_ACTIVE_REG;
  16103. X                }
  16104. X              else
  16105. X                highest_active_reg = r;
  16106. X            }
  16107. X          
  16108. X          /* If just failed to match something this time around with a
  16109. X             group that's operated on by a repetition operator, try to
  16110. X             force exit from the ``loop'', and restore the register
  16111. X             information for this group that we had before trying this
  16112. X             last match.  */
  16113. X          if ((!MATCHED_SOMETHING (reg_info[*p])
  16114. X               || (re_opcode_t) p[-3] == start_memory)
  16115. X          && (p + 2) < pend)              
  16116. X            {
  16117. X              boolean is_a_jump_n = false;
  16118. X              
  16119. X              p1 = p + 2;
  16120. X              mcnt = 0;
  16121. X              switch ((re_opcode_t) *p1++)
  16122. X                {
  16123. X                  case jump_n:
  16124. X            is_a_jump_n = true;
  16125. X                  case pop_failure_jump:
  16126. X          case maybe_pop_jump:
  16127. X          case jump:
  16128. X          case dummy_failure_jump:
  16129. X                    EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16130. X            if (is_a_jump_n)
  16131. X              p1 += 2;
  16132. X                    break;
  16133. X                  
  16134. X                  default:
  16135. X                    /* do nothing */ ;
  16136. X                }
  16137. X          p1 += mcnt;
  16138. X        
  16139. X              /* If the next operation is a jump backwards in the pattern
  16140. X             to an on_failure_jump right before the start_memory
  16141. X                 corresponding to this stop_memory, exit from the loop
  16142. X                 by forcing a failure after pushing on the stack the
  16143. X                 on_failure_jump's jump in the pattern, and d.  */
  16144. X              if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
  16145. X                  && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
  16146. X        {
  16147. X                  /* If this group ever matched anything, then restore
  16148. X                     what its registers were before trying this last
  16149. X                     failed match, e.g., with `(a*)*b' against `ab' for
  16150. X                     regstart[1], and, e.g., with `((a*)*(b*)*)*'
  16151. X                     against `aba' for regend[3].
  16152. X                     
  16153. X                     Also restore the registers for inner groups for,
  16154. X                     e.g., `((a*)(b*))*' against `aba' (register 3 would
  16155. X                     otherwise get trashed).  */
  16156. X                     
  16157. X                  if (EVER_MATCHED_SOMETHING (reg_info[*p]))
  16158. X            {
  16159. X              unsigned r; 
  16160. X        
  16161. X                      EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
  16162. X                      
  16163. X              /* Restore this and inner groups' (if any) registers.  */
  16164. X                      for (r = *p; r < *p + *(p + 1); r++)
  16165. X                        {
  16166. X                          regstart[r] = old_regstart[r];
  16167. X
  16168. X                          /* xx why this test?  */
  16169. X                          if ((int) old_regend[r] >= (int) regstart[r])
  16170. X                            regend[r] = old_regend[r];
  16171. X                        }     
  16172. X                    }
  16173. X          p1++;
  16174. X                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16175. X                  PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
  16176. X
  16177. X                  goto fail;
  16178. X                }
  16179. X            }
  16180. X          
  16181. X          /* Move past the register number and the inner group count.  */
  16182. X          p += 2;
  16183. X          break;
  16184. X
  16185. X
  16186. X    /* \<digit> has been turned into a `duplicate' command which is
  16187. X           followed by the numeric value of <digit> as the register number.  */
  16188. X        case duplicate:
  16189. X      {
  16190. X        register const char *d2, *dend2;
  16191. X        int regno = *p++;   /* Get which register to match against.  */
  16192. X        DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
  16193. X
  16194. X        /* Can't back reference a group which we've never matched.  */
  16195. X            if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
  16196. X              goto fail;
  16197. X              
  16198. X            /* Where in input to try to start matching.  */
  16199. X            d2 = regstart[regno];
  16200. X            
  16201. X            /* Where to stop matching; if both the place to start and
  16202. X               the place to stop matching are in the same string, then
  16203. X               set to the place to stop, otherwise, for now have to use
  16204. X               the end of the first string.  */
  16205. X
  16206. X            dend2 = ((FIRST_STRING_P (regstart[regno]) 
  16207. X              == FIRST_STRING_P (regend[regno]))
  16208. X             ? regend[regno] : end_match_1);
  16209. X        for (;;)
  16210. X          {
  16211. X        /* If necessary, advance to next segment in register
  16212. X                   contents.  */
  16213. X        while (d2 == dend2)
  16214. X          {
  16215. X            if (dend2 == end_match_2) break;
  16216. X            if (dend2 == regend[regno]) break;
  16217. X
  16218. X                    /* End of string1 => advance to string2. */
  16219. X                    d2 = string2;
  16220. X                    dend2 = regend[regno];
  16221. X          }
  16222. X        /* At end of register contents => success */
  16223. X        if (d2 == dend2) break;
  16224. X
  16225. X        /* If necessary, advance to next segment in data.  */
  16226. X        PREFETCH ();
  16227. X
  16228. X        /* How many characters left in this segment to match.  */
  16229. X        mcnt = dend - d;
  16230. X                
  16231. X        /* Want how many consecutive characters we can match in
  16232. X                   one shot, so, if necessary, adjust the count.  */
  16233. X                if (mcnt > dend2 - d2)
  16234. X          mcnt = dend2 - d2;
  16235. X                  
  16236. X        /* Compare that many; failure if mismatch, else move
  16237. X                   past them.  */
  16238. X        if (translate 
  16239. X                    ? bcmp_translate (d, d2, mcnt, translate) 
  16240. X                    : bcmp (d, d2, mcnt))
  16241. X          goto fail;
  16242. X        d += mcnt, d2 += mcnt;
  16243. X          }
  16244. X      }
  16245. X      break;
  16246. X
  16247. X
  16248. X        /* begline matches the empty string at the beginning of the string
  16249. X           (unless `not_bol' is set in `bufp'), and, if
  16250. X           `newline_anchor' is set, after newlines.  */
  16251. X    case begline:
  16252. X          DEBUG_PRINT1 ("EXECUTING begline.\n");
  16253. X          
  16254. X          if (AT_STRINGS_BEG (d))
  16255. X            {
  16256. X              if (!bufp->not_bol) break;
  16257. X            }
  16258. X          else if (d[-1] == '\n' && bufp->newline_anchor)
  16259. X            {
  16260. X              break;
  16261. X            }
  16262. X          /* In all other cases, we fail.  */
  16263. X          goto fail;
  16264. X
  16265. X
  16266. X        /* endline is the dual of begline.  */
  16267. X    case endline:
  16268. X          DEBUG_PRINT1 ("EXECUTING endline.\n");
  16269. X
  16270. X          if (AT_STRINGS_END (d))
  16271. X            {
  16272. X              if (!bufp->not_eol) break;
  16273. X            }
  16274. X          
  16275. X          /* We have to ``prefetch'' the next character.  */
  16276. X          else if ((d == end1 ? *string2 : *d) == '\n'
  16277. X                   && bufp->newline_anchor)
  16278. X            {
  16279. X              break;
  16280. X            }
  16281. X          goto fail;
  16282. X
  16283. X
  16284. X    /* Match at the very beginning of the data.  */
  16285. X        case begbuf:
  16286. X          DEBUG_PRINT1 ("EXECUTING begbuf.\n");
  16287. X          if (AT_STRINGS_BEG (d))
  16288. X            break;
  16289. X          goto fail;
  16290. X
  16291. X
  16292. X    /* Match at the very end of the data.  */
  16293. X        case endbuf:
  16294. X          DEBUG_PRINT1 ("EXECUTING endbuf.\n");
  16295. X      if (AT_STRINGS_END (d))
  16296. X        break;
  16297. X          goto fail;
  16298. X
  16299. X
  16300. X        /* on_failure_keep_string_jump is used to optimize `.*\n'.  It
  16301. X           pushes NULL as the value for the string on the stack.  Then
  16302. X           `pop_failure_point' will keep the current value for the
  16303. X           string, instead of restoring it.  To see why, consider
  16304. X           matching `foo\nbar' against `.*\n'.  The .* matches the foo;
  16305. X           then the . fails against the \n.  But the next thing we want
  16306. X           to do is match the \n against the \n; if we restored the
  16307. X           string value, we would be back at the foo.
  16308. X           
  16309. X           Because this is used only in specific cases, we don't need to
  16310. X           check all the things that `on_failure_jump' does, to make
  16311. X           sure the right things get saved on the stack.  Hence we don't
  16312. X           share its code.  The only reason to push anything on the
  16313. X           stack at all is that otherwise we would have to change
  16314. X           `anychar's code to do something besides goto fail in this
  16315. X           case; that seems worse than this.  */
  16316. X        case on_failure_keep_string_jump:
  16317. X          DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
  16318. X          
  16319. X          EXTRACT_NUMBER_AND_INCR (mcnt, p);
  16320. X          DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
  16321. X
  16322. X          PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
  16323. X          break;
  16324. X
  16325. X
  16326. X    /* Uses of on_failure_jump:
  16327. X        
  16328. X           Each alternative starts with an on_failure_jump that points
  16329. X           to the beginning of the next alternative.  Each alternative
  16330. X           except the last ends with a jump that in effect jumps past
  16331. X           the rest of the alternatives.  (They really jump to the
  16332. X           ending jump of the following alternative, because tensioning
  16333. X           these jumps is a hassle.)
  16334. X
  16335. X           Repeats start with an on_failure_jump that points past both
  16336. X           the repetition text and either the following jump or
  16337. X           pop_failure_jump back to this on_failure_jump.  */
  16338. X    case on_failure_jump:
  16339. X        on_failure:
  16340. X          DEBUG_PRINT1 ("EXECUTING on_failure_jump");
  16341. X
  16342. X          EXTRACT_NUMBER_AND_INCR (mcnt, p);
  16343. X          DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
  16344. X
  16345. X          /* If this on_failure_jump comes right before a group (i.e.,
  16346. X             the original * applied to a group), save the information
  16347. X             for that group and all inner ones, so that if we fail back
  16348. X             to this point, the group's information will be correct.
  16349. X             For example, in \(a*\)*\1, we need the preceding group,
  16350. X             and in \(\(a*\)b*\)\2, we need the inner group.  */
  16351. X
  16352. X          /* We can't use `p' to check ahead because we push
  16353. X             a failure point to `p + mcnt' after we do this.  */
  16354. X          p1 = p;
  16355. X
  16356. X          /* We need to skip no_op's before we look for the
  16357. X             start_memory in case this on_failure_jump is happening as
  16358. X             the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
  16359. X             against aba.  */
  16360. X          while (p1 < pend && (re_opcode_t) *p1 == no_op)
  16361. X            p1++;
  16362. X
  16363. X          if (p1 < pend && (re_opcode_t) *p1 == start_memory)
  16364. X            {
  16365. X              /* We have a new highest active register now.  This will
  16366. X                 get reset at the start_memory we are about to get to,
  16367. X                 but we will have saved all the registers relevant to
  16368. X                 this repetition op, as described above.  */
  16369. X              highest_active_reg = *(p1 + 1) + *(p1 + 2);
  16370. X              if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
  16371. X                lowest_active_reg = *(p1 + 1);
  16372. X            }
  16373. X
  16374. X          DEBUG_PRINT1 (":\n");
  16375. X          PUSH_FAILURE_POINT (p + mcnt, d, -2);
  16376. X          break;
  16377. X
  16378. X
  16379. X        /* A smart repeat ends with `maybe_pop_jump'.
  16380. X       We change it to either `pop_failure_jump' or `jump'.  */
  16381. X        case maybe_pop_jump:
  16382. X          EXTRACT_NUMBER_AND_INCR (mcnt, p);
  16383. X          DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
  16384. X          {
  16385. X        register unsigned char *p2 = p;
  16386. X
  16387. X            /* Compare the beginning of the repeat with what in the
  16388. X               pattern follows its end. If we can establish that there
  16389. X               is nothing that they would both match, i.e., that we
  16390. X               would have to backtrack because of (as in, e.g., `a*a')
  16391. X               then we can change to pop_failure_jump, because we'll
  16392. X               never have to backtrack.
  16393. X               
  16394. X               This is not true in the case of alternatives: in
  16395. X               `(a|ab)*' we do need to backtrack to the `ab' alternative
  16396. X               (e.g., if the string was `ab').  But instead of trying to
  16397. X               detect that here, the alternative has put on a dummy
  16398. X               failure point which is what we will end up popping.  */
  16399. X
  16400. X        /* Skip over open/close-group commands.  */
  16401. X        while (p2 + 2 < pend
  16402. X           && ((re_opcode_t) *p2 == stop_memory
  16403. X               || (re_opcode_t) *p2 == start_memory))
  16404. X          p2 += 3;            /* Skip over args, too.  */
  16405. X
  16406. X            /* If we're at the end of the pattern, we can change.  */
  16407. X            if (p2 == pend)
  16408. X          {
  16409. X        /* Consider what happens when matching ":\(.*\)"
  16410. X           against ":/".  I don't really understand this code
  16411. X           yet.  */
  16412. X              p[-3] = (unsigned char) pop_failure_jump;
  16413. X                DEBUG_PRINT1
  16414. X                  ("  End of pattern: change to `pop_failure_jump'.\n");
  16415. X              }
  16416. X
  16417. X            else if ((re_opcode_t) *p2 == exactn
  16418. X             || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
  16419. X          {
  16420. X        register unsigned char c
  16421. X                  = *p2 == (unsigned char) endline ? '\n' : p2[2];
  16422. X        p1 = p + mcnt;
  16423. X
  16424. X                /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
  16425. X                   to the `maybe_finalize_jump' of this case.  Examine what 
  16426. X                   follows.  */
  16427. X                if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
  16428. X                  {
  16429. X              p[-3] = (unsigned char) pop_failure_jump;
  16430. X                    DEBUG_PRINT3 ("  %c != %c => pop_failure_jump.\n",
  16431. X                                  c, p1[5]);
  16432. X                  }
  16433. X                  
  16434. X        else if ((re_opcode_t) p1[3] == charset
  16435. X             || (re_opcode_t) p1[3] == charset_not)
  16436. X          {
  16437. X            int not = (re_opcode_t) p1[3] == charset_not;
  16438. X                    
  16439. X            if (c < (unsigned char) (p1[4] * BYTEWIDTH)
  16440. X            && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
  16441. X              not = !not;
  16442. X
  16443. X                    /* `not' is equal to 1 if c would match, which means
  16444. X                        that we can't change to pop_failure_jump.  */
  16445. X            if (!not)
  16446. X                      {
  16447. X                  p[-3] = (unsigned char) pop_failure_jump;
  16448. X                        DEBUG_PRINT1 ("  No match => pop_failure_jump.\n");
  16449. X                      }
  16450. X          }
  16451. X          }
  16452. X      }
  16453. X      p -= 2;        /* Point at relative address again.  */
  16454. X      if ((re_opcode_t) p[-1] != pop_failure_jump)
  16455. X        {
  16456. X          p[-1] = (unsigned char) jump;
  16457. X              DEBUG_PRINT1 ("  Match => jump.\n");
  16458. X          goto unconditional_jump;
  16459. X        }
  16460. X        /* Note fall through.  */
  16461. X
  16462. X
  16463. X    /* The end of a simple repeat has a pop_failure_jump back to
  16464. X           its matching on_failure_jump, where the latter will push a
  16465. X           failure point.  The pop_failure_jump takes off failure
  16466. X           points put on by this pop_failure_jump's matching
  16467. X           on_failure_jump; we got through the pattern to here from the
  16468. X           matching on_failure_jump, so didn't fail.  */
  16469. X        case pop_failure_jump:
  16470. X          {
  16471. X            /* We need to pass separate storage for the lowest and
  16472. X               highest registers, even though we don't care about the
  16473. X               actual values.  Otherwise, we will restore only one
  16474. X               register from the stack, since lowest will == highest in
  16475. X               `pop_failure_point'.  */
  16476. X            unsigned dummy_low_reg, dummy_high_reg;
  16477. X            unsigned char *pdummy;
  16478. X            const char *sdummy;
  16479. X
  16480. X            DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
  16481. X            POP_FAILURE_POINT (sdummy, pdummy,
  16482. X                               dummy_low_reg, dummy_high_reg,
  16483. X                               reg_dummy, reg_dummy, reg_info_dummy);
  16484. X          }
  16485. X          /* Note fall through.  */
  16486. X
  16487. X          
  16488. X        /* Unconditionally jump (without popping any failure points).  */
  16489. X        case jump:
  16490. X    unconditional_jump:
  16491. X      EXTRACT_NUMBER_AND_INCR (mcnt, p);    /* Get the amount to jump.  */
  16492. X          DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
  16493. X      p += mcnt;                /* Do the jump.  */
  16494. X          DEBUG_PRINT2 ("(to 0x%x).\n", p);
  16495. X      break;
  16496. X
  16497. X    
  16498. X        /* We need this opcode so we can detect where alternatives end
  16499. X           in `group_match_null_string_p' et al.  */
  16500. X        case jump_past_alt:
  16501. X          DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
  16502. X          goto unconditional_jump;
  16503. X
  16504. X
  16505. X        /* Normally, the on_failure_jump pushes a failure point, which
  16506. X           then gets popped at pop_failure_jump.  We will end up at
  16507. X           pop_failure_jump, also, and with a pattern of, say, `a+', we
  16508. X           are skipping over the on_failure_jump, so we have to push
  16509. X           something meaningless for pop_failure_jump to pop.  */
  16510. X        case dummy_failure_jump:
  16511. X          DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
  16512. X          /* It doesn't matter what we push for the string here.  What
  16513. X             the code at `fail' tests is the value for the pattern.  */
  16514. X          PUSH_FAILURE_POINT (0, 0, -2);
  16515. X          goto unconditional_jump;
  16516. X
  16517. X
  16518. X        /* At the end of an alternative, we need to push a dummy failure
  16519. X           point in case we are followed by a `pop_failure_jump', because
  16520. X           we don't want the failure point for the alternative to be
  16521. X           popped.  For example, matching `(a|ab)*' against `aab'
  16522. X           requires that we match the `ab' alternative.  */
  16523. X        case push_dummy_failure:
  16524. X          DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
  16525. X          /* See comments just above at `dummy_failure_jump' about the
  16526. X             two zeroes.  */
  16527. X          PUSH_FAILURE_POINT (0, 0, -2);
  16528. X          break;
  16529. X
  16530. X        /* Have to succeed matching what follows at least n times.
  16531. X           After that, handle like `on_failure_jump'.  */
  16532. X        case succeed_n: 
  16533. X          EXTRACT_NUMBER (mcnt, p + 2);
  16534. X          DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
  16535. X
  16536. X          assert (mcnt >= 0);
  16537. X          /* Originally, this is how many times we HAVE to succeed.  */
  16538. X          if (mcnt > 0)
  16539. X            {
  16540. X               mcnt--;
  16541. X           p += 2;
  16542. X               STORE_NUMBER_AND_INCR (p, mcnt);
  16543. X               DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p, mcnt);
  16544. X            }
  16545. X      else if (mcnt == 0)
  16546. X            {
  16547. X              DEBUG_PRINT2 ("  Setting two bytes from 0x%x to no_op.\n", p+2);
  16548. X          p[2] = (unsigned char) no_op;
  16549. X              p[3] = (unsigned char) no_op;
  16550. X              goto on_failure;
  16551. X            }
  16552. X          break;
  16553. X        
  16554. X        case jump_n: 
  16555. X          EXTRACT_NUMBER (mcnt, p + 2);
  16556. X          DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
  16557. X
  16558. X          /* Originally, this is how many times we CAN jump.  */
  16559. X          if (mcnt)
  16560. X            {
  16561. X               mcnt--;
  16562. X               STORE_NUMBER (p + 2, mcnt);
  16563. X           goto unconditional_jump;         
  16564. X            }
  16565. X          /* If don't have to jump any more, skip over the rest of command.  */
  16566. X      else      
  16567. X        p += 4;             
  16568. X          break;
  16569. X        
  16570. X    case set_number_at:
  16571. X      {
  16572. X            DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
  16573. X
  16574. X            EXTRACT_NUMBER_AND_INCR (mcnt, p);
  16575. X            p1 = p + mcnt;
  16576. X            EXTRACT_NUMBER_AND_INCR (mcnt, p);
  16577. X            DEBUG_PRINT3 ("  Setting 0x%x to %d.\n", p1, mcnt);
  16578. X        STORE_NUMBER (p1, mcnt);
  16579. X            break;
  16580. X          }
  16581. X
  16582. X        case wordbound:
  16583. X          DEBUG_PRINT1 ("EXECUTING wordbound.\n");
  16584. X          if (AT_WORD_BOUNDARY (d))
  16585. X        break;
  16586. X          goto fail;
  16587. X
  16588. X    case notwordbound:
  16589. X          DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
  16590. X      if (AT_WORD_BOUNDARY (d))
  16591. X        goto fail;
  16592. X          break;
  16593. X
  16594. X    case wordbeg:
  16595. X          DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
  16596. X      if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
  16597. X        break;
  16598. X          goto fail;
  16599. X
  16600. X    case wordend:
  16601. X          DEBUG_PRINT1 ("EXECUTING wordend.\n");
  16602. X      if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
  16603. X              && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
  16604. X        break;
  16605. X          goto fail;
  16606. X
  16607. X#ifdef emacs
  16608. X#ifdef emacs19
  16609. X      case before_dot:
  16610. X          DEBUG_PRINT1 ("EXECUTING before_dot.\n");
  16611. X       if (PTR_CHAR_POS ((unsigned char *) d) >= point)
  16612. X          goto fail;
  16613. X        break;
  16614. X  
  16615. X      case at_dot:
  16616. X          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
  16617. X       if (PTR_CHAR_POS ((unsigned char *) d) != point)
  16618. X          goto fail;
  16619. X        break;
  16620. X  
  16621. X      case after_dot:
  16622. X          DEBUG_PRINT1 ("EXECUTING after_dot.\n");
  16623. X          if (PTR_CHAR_POS ((unsigned char *) d) <= point)
  16624. X          goto fail;
  16625. X        break;
  16626. X#else /* not emacs19 */
  16627. X    case at_dot:
  16628. X          DEBUG_PRINT1 ("EXECUTING at_dot.\n");
  16629. X      if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
  16630. X        goto fail;
  16631. X      break;
  16632. X#endif /* not emacs19 */
  16633. X
  16634. X    case syntaxspec:
  16635. X          DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
  16636. X      mcnt = *p++;
  16637. X      goto matchsyntax;
  16638. X
  16639. X        case wordchar:
  16640. X          DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
  16641. X      mcnt = (int) Sword;
  16642. X        matchsyntax:
  16643. X      PREFETCH ();
  16644. X      if (SYNTAX (*d++) != (enum syntaxcode) mcnt)
  16645. X            goto fail;
  16646. X          SET_REGS_MATCHED ();
  16647. X      break;
  16648. X
  16649. X    case notsyntaxspec:
  16650. X          DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
  16651. X      mcnt = *p++;
  16652. X      goto matchnotsyntax;
  16653. X
  16654. X        case notwordchar:
  16655. X          DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
  16656. X      mcnt = (int) Sword;
  16657. X        matchnotsyntax:
  16658. X      PREFETCH ();
  16659. X      if (SYNTAX (*d++) == (enum syntaxcode) mcnt)
  16660. X            goto fail;
  16661. X      SET_REGS_MATCHED ();
  16662. X          break;
  16663. X
  16664. X#else /* not emacs */
  16665. X    case wordchar:
  16666. X          DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
  16667. X      PREFETCH ();
  16668. X          if (!WORDCHAR_P (d))
  16669. X            goto fail;
  16670. X      SET_REGS_MATCHED ();
  16671. X          d++;
  16672. X      break;
  16673. X      
  16674. X    case notwordchar:
  16675. X          DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
  16676. X      PREFETCH ();
  16677. X      if (WORDCHAR_P (d))
  16678. X            goto fail;
  16679. X          SET_REGS_MATCHED ();
  16680. X          d++;
  16681. X      break;
  16682. X#endif /* not emacs */
  16683. X          
  16684. X        default:
  16685. X          abort ();
  16686. X    }
  16687. X      continue;  /* Successfully executed one pattern command; keep going.  */
  16688. X
  16689. X
  16690. X    /* We goto here if a matching operation fails. */
  16691. X    fail:
  16692. X      if (!FAIL_STACK_EMPTY ())
  16693. X    { /* A restart point is known.  Restore to that state.  */
  16694. X          DEBUG_PRINT1 ("\nFAIL:\n");
  16695. X          POP_FAILURE_POINT (d, p,
  16696. X                             lowest_active_reg, highest_active_reg,
  16697. X                             regstart, regend, reg_info);
  16698. X
  16699. X          /* If this failure point is a dummy, try the next one.  */
  16700. X          if (!p)
  16701. X        goto fail;
  16702. X
  16703. X          /* If we failed to the end of the pattern, don't examine *p.  */
  16704. X      assert (p <= pend);
  16705. X          if (p < pend)
  16706. X            {
  16707. X              boolean is_a_jump_n = false;
  16708. X              
  16709. X              /* If failed to a backwards jump that's part of a repetition
  16710. X                 loop, need to pop this failure point and use the next one.  */
  16711. X              switch ((re_opcode_t) *p)
  16712. X                {
  16713. X                case jump_n:
  16714. X                  is_a_jump_n = true;
  16715. X                case maybe_pop_jump:
  16716. X                case pop_failure_jump:
  16717. X                case jump:
  16718. X                  p1 = p + 1;
  16719. X                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16720. X                  p1 += mcnt;    
  16721. X
  16722. X                  if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
  16723. X                      || (!is_a_jump_n
  16724. X                          && (re_opcode_t) *p1 == on_failure_jump))
  16725. X                    goto fail;
  16726. X                  break;
  16727. X                default:
  16728. X                  /* do nothing */ ;
  16729. X                }
  16730. X            }
  16731. X
  16732. X          if (d >= string1 && d <= end1)
  16733. X        dend = end_match_1;
  16734. X        }
  16735. X      else
  16736. X        break;   /* Matching at this starting point really fails.  */
  16737. X    } /* for (;;) */
  16738. X
  16739. X  if (best_regs_set)
  16740. X    goto restore_best_regs;
  16741. X
  16742. X  FREE_VARIABLES ();
  16743. X
  16744. X  return -1;                     /* Failure to match.  */
  16745. X} /* re_match_2 */
  16746. X
  16747. X/* Subroutine definitions for re_match_2.  */
  16748. X
  16749. X
  16750. X/* We are passed P pointing to a register number after a start_memory.
  16751. X   
  16752. X   Return true if the pattern up to the corresponding stop_memory can
  16753. X   match the empty string, and false otherwise.
  16754. X   
  16755. X   If we find the matching stop_memory, sets P to point to one past its number.
  16756. X   Otherwise, sets P to an undefined byte less than or equal to END.
  16757. X
  16758. X   We don't handle duplicates properly (yet).  */
  16759. X
  16760. Xstatic boolean
  16761. Xgroup_match_null_string_p (p, end, reg_info)
  16762. X    unsigned char **p, *end;
  16763. X    register_info_type *reg_info;
  16764. X{
  16765. X  int mcnt;
  16766. X  /* Point to after the args to the start_memory.  */
  16767. X  unsigned char *p1 = *p + 2;
  16768. X  
  16769. X  while (p1 < end)
  16770. X    {
  16771. X      /* Skip over opcodes that can match nothing, and return true or
  16772. X     false, as appropriate, when we get to one that can't, or to the
  16773. X         matching stop_memory.  */
  16774. X      
  16775. X      switch ((re_opcode_t) *p1)
  16776. X        {
  16777. X        /* Could be either a loop or a series of alternatives.  */
  16778. X        case on_failure_jump:
  16779. X          p1++;
  16780. X          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16781. X          
  16782. X          /* If the next operation is not a jump backwards in the
  16783. X         pattern.  */
  16784. X
  16785. X      if (mcnt >= 0)
  16786. X        {
  16787. X              /* Go through the on_failure_jumps of the alternatives,
  16788. X                 seeing if any of the alternatives cannot match nothing.
  16789. X                 The last alternative starts with only a jump,
  16790. X                 whereas the rest start with on_failure_jump and end
  16791. X                 with a jump, e.g., here is the pattern for `a|b|c':
  16792. X
  16793. X                 /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
  16794. X                 /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
  16795. X                 /exactn/1/c                        
  16796. X
  16797. X                 So, we have to first go through the first (n-1)
  16798. X                 alternatives and then deal with the last one separately.  */
  16799. X
  16800. X
  16801. X              /* Deal with the first (n-1) alternatives, which start
  16802. X                 with an on_failure_jump (see above) that jumps to right
  16803. X                 past a jump_past_alt.  */
  16804. X
  16805. X              while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
  16806. X                {
  16807. X                  /* `mcnt' holds how many bytes long the alternative
  16808. X                     is, including the ending `jump_past_alt' and
  16809. X                     its number.  */
  16810. X
  16811. X                  if (!alt_match_null_string_p (p1, p1 + mcnt - 3, 
  16812. X                                      reg_info))
  16813. X                    return false;
  16814. X
  16815. X                  /* Move to right after this alternative, including the
  16816. X             jump_past_alt.  */
  16817. X                  p1 += mcnt;    
  16818. X
  16819. X                  /* Break if it's the beginning of an n-th alternative
  16820. X                     that doesn't begin with an on_failure_jump.  */
  16821. X                  if ((re_opcode_t) *p1 != on_failure_jump)
  16822. X                    break;
  16823. X        
  16824. X          /* Still have to check that it's not an n-th
  16825. X             alternative that starts with an on_failure_jump.  */
  16826. X          p1++;
  16827. X                  EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16828. X                  if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
  16829. X                    {
  16830. X              /* Get to the beginning of the n-th alternative.  */
  16831. X                      p1 -= 3;
  16832. X                      break;
  16833. X                    }
  16834. X                }
  16835. X
  16836. X              /* Deal with the last alternative: go back and get number
  16837. X                 of the `jump_past_alt' just before it.  `mcnt' contains
  16838. X                 the length of the alternative.  */
  16839. X              EXTRACT_NUMBER (mcnt, p1 - 2);
  16840. X
  16841. X              if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
  16842. X                return false;
  16843. X
  16844. X              p1 += mcnt;    /* Get past the n-th alternative.  */
  16845. X            } /* if mcnt > 0 */
  16846. X          break;
  16847. X
  16848. X          
  16849. X        case stop_memory:
  16850. X      assert (p1[1] == **p);
  16851. X          *p = p1 + 2;
  16852. X          return true;
  16853. X
  16854. X        
  16855. X        default: 
  16856. X          if (!common_op_match_null_string_p (&p1, end, reg_info))
  16857. X            return false;
  16858. X        }
  16859. X    } /* while p1 < end */
  16860. X
  16861. X  return false;
  16862. X} /* group_match_null_string_p */
  16863. X
  16864. X
  16865. X/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
  16866. X   It expects P to be the first byte of a single alternative and END one
  16867. X   byte past the last. The alternative can contain groups.  */
  16868. X   
  16869. Xstatic boolean
  16870. Xalt_match_null_string_p (p, end, reg_info)
  16871. X    unsigned char *p, *end;
  16872. X    register_info_type *reg_info;
  16873. X{
  16874. X  int mcnt;
  16875. X  unsigned char *p1 = p;
  16876. X  
  16877. X  while (p1 < end)
  16878. X    {
  16879. X      /* Skip over opcodes that can match nothing, and break when we get 
  16880. X         to one that can't.  */
  16881. X      
  16882. X      switch ((re_opcode_t) *p1)
  16883. X        {
  16884. X    /* It's a loop.  */
  16885. X        case on_failure_jump:
  16886. X          p1++;
  16887. X          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16888. X          p1 += mcnt;
  16889. X          break;
  16890. X          
  16891. X    default: 
  16892. X          if (!common_op_match_null_string_p (&p1, end, reg_info))
  16893. X            return false;
  16894. X        }
  16895. X    }  /* while p1 < end */
  16896. X
  16897. X  return true;
  16898. X} /* alt_match_null_string_p */
  16899. X
  16900. X
  16901. X/* Deals with the ops common to group_match_null_string_p and
  16902. X   alt_match_null_string_p.  
  16903. X   
  16904. X   Sets P to one after the op and its arguments, if any.  */
  16905. X
  16906. Xstatic boolean
  16907. Xcommon_op_match_null_string_p (p, end, reg_info)
  16908. X    unsigned char **p, *end;
  16909. X    register_info_type *reg_info;
  16910. X{
  16911. X  int mcnt;
  16912. X  boolean ret;
  16913. X  int reg_no;
  16914. X  unsigned char *p1 = *p;
  16915. X
  16916. X  switch ((re_opcode_t) *p1++)
  16917. X    {
  16918. X    case no_op:
  16919. X    case begline:
  16920. X    case endline:
  16921. X    case begbuf:
  16922. X    case endbuf:
  16923. X    case wordbeg:
  16924. X    case wordend:
  16925. X    case wordbound:
  16926. X    case notwordbound:
  16927. X#ifdef emacs
  16928. X    case before_dot:
  16929. X    case at_dot:
  16930. X    case after_dot:
  16931. X#endif
  16932. X      break;
  16933. X
  16934. X    case start_memory:
  16935. X      reg_no = *p1;
  16936. X      assert (reg_no > 0 && reg_no <= MAX_REGNUM);
  16937. X      ret = group_match_null_string_p (&p1, end, reg_info);
  16938. X      
  16939. X      /* Have to set this here in case we're checking a group which
  16940. X         contains a group and a back reference to it.  */
  16941. X
  16942. X      if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
  16943. X        REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
  16944. X
  16945. X      if (!ret)
  16946. X        return false;
  16947. X      break;
  16948. X          
  16949. X    /* If this is an optimized succeed_n for zero times, make the jump.  */
  16950. X    case jump:
  16951. X      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16952. X      if (mcnt >= 0)
  16953. X        p1 += mcnt;
  16954. X      else
  16955. X        return false;
  16956. X      break;
  16957. X
  16958. X    case succeed_n:
  16959. X      /* Get to the number of times to succeed.  */
  16960. X      p1 += 2;        
  16961. X      EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16962. X
  16963. X      if (mcnt == 0)
  16964. X        {
  16965. X          p1 -= 4;
  16966. X          EXTRACT_NUMBER_AND_INCR (mcnt, p1);
  16967. X          p1 += mcnt;
  16968. X        }
  16969. X      else
  16970. X        return false;
  16971. X      break;
  16972. X
  16973. X    case duplicate: 
  16974. X      if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
  16975. X        return false;
  16976. X      break;
  16977. X
  16978. X    case set_number_at:
  16979. X      p1 += 4;
  16980. X
  16981. X    default:
  16982. X      /* All other opcodes mean we cannot match the empty string.  */
  16983. X      return false;
  16984. X  }
  16985. X
  16986. X  *p = p1;
  16987. X  return true;
  16988. X} /* common_op_match_null_string_p */
  16989. X
  16990. X
  16991. X/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
  16992. X   bytes; nonzero otherwise.  */
  16993. X   
  16994. Xstatic int
  16995. Xbcmp_translate (s1, s2, len, translate)
  16996. X     unsigned char *s1, *s2;
  16997. X     register int len;
  16998. X     char *translate;
  16999. X{
  17000. X  register unsigned char *p1 = s1, *p2 = s2;
  17001. X  while (len)
  17002. X    {
  17003. X      if (translate[*p1++] != translate[*p2++]) return 1;
  17004. X      len--;
  17005. X    }
  17006. X  return 0;
  17007. X}
  17008. X
  17009. X/* Entry points for GNU code.  */
  17010. X
  17011. X/* re_compile_pattern is the GNU regular expression compiler: it
  17012. X   compiles PATTERN (of length SIZE) and puts the result in BUFP.
  17013. X   Returns 0 if the pattern was valid, otherwise an error string.
  17014. X   
  17015. X   Assumes the `allocated' (and perhaps `buffer') and `translate' fields
  17016. X   are set in BUFP on entry.
  17017. X   
  17018. X   We call regex_compile to do the actual compilation.  */
  17019. X
  17020. Xconst char *
  17021. Xre_compile_pattern (pattern, length, bufp)
  17022. X     const char *pattern;
  17023. X     int length;
  17024. X     struct re_pattern_buffer *bufp;
  17025. X{
  17026. X  reg_errcode_t ret;
  17027. X  
  17028. X  /* GNU code is written to assume at least RE_NREGS registers will be set
  17029. X     (and at least one extra will be -1).  */
  17030. X  bufp->regs_allocated = REGS_UNALLOCATED;
  17031. X  
  17032. X  /* And GNU code determines whether or not to get register information
  17033. X     by passing null for the REGS argument to re_match, etc., not by
  17034. X     setting no_sub.  */
  17035. X  bufp->no_sub = 0;
  17036. X  
  17037. X  /* Match anchors at newline.  */
  17038. X  bufp->newline_anchor = 1;
  17039. X  
  17040. X  ret = regex_compile (pattern, length, re_syntax_options, bufp);
  17041. X
  17042. X  return re_error_msg[(int) ret];
  17043. X}     
  17044. X
  17045. X/* Entry points compatible with 4.2 BSD regex library.  We don't define
  17046. X   them if this is an Emacs or POSIX compilation.  */
  17047. X
  17048. X#if !defined (emacs) && !defined (_POSIX_SOURCE)
  17049. X
  17050. X/* BSD has one and only one pattern buffer.  */
  17051. Xstatic struct re_pattern_buffer re_comp_buf;
  17052. X
  17053. Xchar *
  17054. Xre_comp (s)
  17055. X    const char *s;
  17056. X{
  17057. X  reg_errcode_t ret;
  17058. X  
  17059. X  if (!s)
  17060. X    {
  17061. X      if (!re_comp_buf.buffer)
  17062. X    return "No previous regular expression";
  17063. X      return 0;
  17064. X    }
  17065. X
  17066. X  if (!re_comp_buf.buffer)
  17067. X    {
  17068. X      re_comp_buf.buffer = (unsigned char *) malloc (200);
  17069. X      if (re_comp_buf.buffer == NULL)
  17070. X        return "Memory exhausted";
  17071. X      re_comp_buf.allocated = 200;
  17072. X
  17073. X      re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
  17074. X      if (re_comp_buf.fastmap == NULL)
  17075. X    return "Memory exhausted";
  17076. X    }
  17077. X
  17078. X  /* Since `re_exec' always passes NULL for the `regs' argument, we
  17079. X     don't need to initialize the pattern buffer fields which affect it.  */
  17080. X
  17081. X  /* Match anchors at newlines.  */
  17082. X  re_comp_buf.newline_anchor = 1;
  17083. X
  17084. X  ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
  17085. X  
  17086. X  /* Yes, we're discarding `const' here.  */
  17087. X  return (char *) re_error_msg[(int) ret];
  17088. X}
  17089. X
  17090. X
  17091. Xint
  17092. Xre_exec (s)
  17093. X    const char *s;
  17094. X{
  17095. X  const int len = strlen (s);
  17096. X  return
  17097. X    0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
  17098. X}
  17099. X#endif /* not emacs and not _POSIX_SOURCE */
  17100. X
  17101. X/* POSIX.2 functions.  Don't define these for Emacs.  */
  17102. X
  17103. X#ifndef emacs
  17104. X
  17105. X/* regcomp takes a regular expression as a string and compiles it.
  17106. X
  17107. X   PREG is a regex_t *.  We do not expect any fields to be initialized,
  17108. X   since POSIX says we shouldn't.  Thus, we set
  17109. X
  17110. X     `buffer' to the compiled pattern;
  17111. X     `used' to the length of the compiled pattern;
  17112. X     `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
  17113. X       REG_EXTENDED bit in CFLAGS is set; otherwise, to
  17114. X       RE_SYNTAX_POSIX_BASIC;
  17115. X     `newline_anchor' to REG_NEWLINE being set in CFLAGS;
  17116. X     `fastmap' and `fastmap_accurate' to zero;
  17117. X     `re_nsub' to the number of subexpressions in PATTERN.
  17118. X
  17119. X   PATTERN is the address of the pattern string.
  17120. X
  17121. X   CFLAGS is a series of bits which affect compilation.
  17122. X
  17123. X     If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
  17124. X     use POSIX basic syntax.
  17125. X
  17126. X     If REG_NEWLINE is set, then . and [^...] don't match newline.
  17127. X     Also, regexec will try a match beginning after every newline.
  17128. X
  17129. X     If REG_ICASE is set, then we considers upper- and lowercase
  17130. X     versions of letters to be equivalent when matching.
  17131. X
  17132. X     If REG_NOSUB is set, then when PREG is passed to regexec, that
  17133. X     routine will report only success or failure, and nothing about the
  17134. X     registers.
  17135. X
  17136. X   It returns 0 if it succeeds, nonzero if it doesn't.  (See regex.h for
  17137. X   the return codes and their meanings.)  */
  17138. X
  17139. Xint
  17140. Xregcomp (preg, pattern, cflags)
  17141. X    regex_t *preg;
  17142. X    const char *pattern; 
  17143. X    int cflags;
  17144. X{
  17145. X  reg_errcode_t ret;
  17146. X  unsigned syntax
  17147. X    = (cflags & REG_EXTENDED) ?
  17148. X      RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
  17149. X
  17150. X  /* regex_compile will allocate the space for the compiled pattern.  */
  17151. X  preg->buffer = 0;
  17152. X  preg->allocated = 0;
  17153. X  
  17154. X  /* Don't bother to use a fastmap when searching.  This simplifies the
  17155. X     REG_NEWLINE case: if we used a fastmap, we'd have to put all the
  17156. X     characters after newlines into the fastmap.  This way, we just try
  17157. X     every character.  */
  17158. X  preg->fastmap = 0;
  17159. X  
  17160. X  if (cflags & REG_ICASE)
  17161. X    {
  17162. X      unsigned i;
  17163. X      
  17164. X      preg->translate = (char *) malloc (CHAR_SET_SIZE);
  17165. X      if (preg->translate == NULL)
  17166. X        return (int) REG_ESPACE;
  17167. X
  17168. X      /* Map uppercase characters to corresponding lowercase ones.  */
  17169. X      for (i = 0; i < CHAR_SET_SIZE; i++)
  17170. X        preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
  17171. X    }
  17172. X  else
  17173. X    preg->translate = NULL;
  17174. X
  17175. X  /* If REG_NEWLINE is set, newlines are treated differently.  */
  17176. X  if (cflags & REG_NEWLINE)
  17177. X    { /* REG_NEWLINE implies neither . nor [^...] match newline.  */
  17178. X      syntax &= ~RE_DOT_NEWLINE;
  17179. X      syntax |= RE_HAT_LISTS_NOT_NEWLINE;
  17180. X      /* It also changes the matching behavior.  */
  17181. X      preg->newline_anchor = 1;
  17182. X    }
  17183. X  else
  17184. X    preg->newline_anchor = 0;
  17185. X
  17186. X  preg->no_sub = !!(cflags & REG_NOSUB);
  17187. X
  17188. X  /* POSIX says a null character in the pattern terminates it, so we 
  17189. X     can use strlen here in compiling the pattern.  */
  17190. X  ret = regex_compile (pattern, strlen (pattern), syntax, preg);
  17191. X  
  17192. X  /* POSIX doesn't distinguish between an unmatched open-group and an
  17193. X     unmatched close-group: both are REG_EPAREN.  */
  17194. X  if (ret == REG_ERPAREN) ret = REG_EPAREN;
  17195. X  
  17196. X  return (int) ret;
  17197. X}
  17198. X
  17199. X
  17200. X/* regexec searches for a given pattern, specified by PREG, in the
  17201. X   string STRING.
  17202. X   
  17203. X   If NMATCH is zero or REG_NOSUB was set in the cflags argument to
  17204. X   `regcomp', we ignore PMATCH.  Otherwise, we assume PMATCH has at
  17205. X   least NMATCH elements, and we set them to the offsets of the
  17206. X   corresponding matched substrings.
  17207. X   
  17208. X   EFLAGS specifies `execution flags' which affect matching: if
  17209. X   REG_NOTBOL is set, then ^ does not match at the beginning of the
  17210. X   string; if REG_NOTEOL is set, then $ does not match at the end.
  17211. X   
  17212. X   We return 0 if we find a match and REG_NOMATCH if not.  */
  17213. X
  17214. Xint
  17215. Xregexec (preg, string, nmatch, pmatch, eflags)
  17216. X    const regex_t *preg;
  17217. X    const char *string; 
  17218. X    size_t nmatch; 
  17219. X    regmatch_t pmatch[]; 
  17220. X    int eflags;
  17221. X{
  17222. X  int ret;
  17223. X  struct re_registers regs;
  17224. X  regex_t private_preg;
  17225. X  int len = strlen (string);
  17226. X  boolean want_reg_info = !preg->no_sub && nmatch > 0;
  17227. X
  17228. X  private_preg = *preg;
  17229. X  
  17230. X  private_preg.not_bol = !!(eflags & REG_NOTBOL);
  17231. X  private_preg.not_eol = !!(eflags & REG_NOTEOL);
  17232. X  
  17233. X  /* The user has told us exactly how many registers to return
  17234. X     information about, via `nmatch'.  We have to pass that on to the
  17235. X     matching routines.  */
  17236. X  private_preg.regs_allocated = REGS_FIXED;
  17237. X  
  17238. X  if (want_reg_info)
  17239. X    {
  17240. X      regs.num_regs = nmatch;
  17241. X      regs.start = TALLOC (nmatch, regoff_t);
  17242. X      regs.end = TALLOC (nmatch, regoff_t);
  17243. X      if (regs.start == NULL || regs.end == NULL)
  17244. X        return (int) REG_NOMATCH;
  17245. X    }
  17246. X
  17247. X  /* Perform the searching operation.  */
  17248. X  ret = re_search (&private_preg, string, len,
  17249. X                   /* start: */ 0, /* range: */ len,
  17250. X                   want_reg_info ? ®s : (struct re_registers *) 0);
  17251. X  
  17252. X  /* Copy the register information to the POSIX structure.  */
  17253. X  if (want_reg_info)
  17254. X    {
  17255. X      if (ret >= 0)
  17256. X        {
  17257. X          unsigned r;
  17258. X
  17259. X          for (r = 0; r < nmatch; r++)
  17260. X            {
  17261. X              pmatch[r].rm_so = regs.start[r];
  17262. X              pmatch[r].rm_eo = regs.end[r];
  17263. X            }
  17264. X        }
  17265. X
  17266. X      /* If we needed the temporary register info, free the space now.  */
  17267. X      free (regs.start);
  17268. X      free (regs.end);
  17269. X    }
  17270. X
  17271. X  /* We want zero return to mean success, unlike `re_search'.  */
  17272. X  return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
  17273. X}
  17274. X
  17275. X
  17276. X/* Returns a message corresponding to an error code, ERRCODE, returned
  17277. X   from either regcomp or regexec.   We don't use PREG here.  */
  17278. X
  17279. Xsize_t
  17280. Xregerror (errcode, preg, errbuf, errbuf_size)
  17281. X    int errcode;
  17282. X    const regex_t *preg;
  17283. X    char *errbuf;
  17284. X    size_t errbuf_size;
  17285. X{
  17286. X  const char *msg;
  17287. X  size_t msg_size;
  17288. X
  17289. X  if (errcode < 0
  17290. X      || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
  17291. X    /* Only error codes returned by the rest of the code should be passed 
  17292. X       to this routine.  If we are given anything else, or if other regex
  17293. X       code generates an invalid error code, then the program has a bug.
  17294. X       Dump core so we can fix it.  */
  17295. X    abort ();
  17296. X
  17297. X  msg_size = strlen (msg) + 1; /* Includes the null.  */
  17298. X  
  17299. X  if (errbuf_size != 0)
  17300. X    {
  17301. X      if (msg_size > errbuf_size)
  17302. X        {
  17303. X          strncpy (errbuf, msg, errbuf_size - 1);
  17304. X          errbuf[errbuf_size - 1] = 0;
  17305. X        }
  17306. X      else
  17307. X        strcpy (errbuf, msg);
  17308. X    }
  17309. X
  17310. X  return msg_size;
  17311. X}
  17312. X
  17313. X
  17314. X/* Free dynamically allocated space used by PREG.  */
  17315. X
  17316. Xvoid
  17317. Xregfree (preg)
  17318. X    regex_t *preg;
  17319. X{
  17320. X  if (preg->buffer != NULL)
  17321. X    free (preg->buffer);
  17322. X  preg->buffer = NULL;
  17323. X  
  17324. X  preg->allocated = 0;
  17325. X  preg->used = 0;
  17326. X
  17327. X  if (preg->fastmap != NULL)
  17328. X    free (preg->fastmap);
  17329. X  preg->fastmap = NULL;
  17330. X  preg->fastmap_accurate = 0;
  17331. X
  17332. X  if (preg->translate != NULL)
  17333. X    free (preg->translate);
  17334. X  preg->translate = NULL;
  17335. X}
  17336. X
  17337. X#endif /* not emacs  */
  17338. X
  17339. X/*
  17340. XLocal variables:
  17341. Xmake-backup-files: t
  17342. Xversion-control: t
  17343. Xtrim-versions-without-asking: nil
  17344. XEnd:
  17345. X*/
  17346. END_OF_FILE
  17347. if test 161195 -ne `wc -c <'regex.c'`; then
  17348.     echo shar: \"'regex.c'\" unpacked with wrong size!
  17349. fi
  17350. # end of 'regex.c'
  17351. fi
  17352. if test -f 'getdate.y' -a "${1}" != "-c" ; then 
  17353.   echo shar: Will not clobber existing file \"'getdate.y'\"
  17354. else
  17355. echo shar: Extracting \"'getdate.y'\" \(22885 characters\)
  17356. sed "s/^X//" >'getdate.y' <<'END_OF_FILE'
  17357. X%{
  17358. X/* $Revision: 2.1 $
  17359. X**
  17360. X**  Originally written by Steven M. Bellovin <smb@research.att.com> while
  17361. X**  at the University of North Carolina at Chapel Hill.  Later tweaked by
  17362. X**  a couple of people on Usenet.  Completely overhauled by Rich $alz
  17363. X**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
  17364. X**  send any email to Rich.
  17365. X**
  17366. X**  This grammar has eight shift/reduce conflicts.
  17367. X**
  17368. X**  This code is in the public domain and has no copyright.
  17369. X*/
  17370. X/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
  17371. X/* SUPPRESS 288 on yyerrlab *//* Label unused */
  17372. X
  17373. X#ifdef HAVE_CONFIG_H
  17374. X#include "config.h"
  17375. X#endif
  17376. X
  17377. X#ifdef __GNUC__
  17378. X#define alloca __builtin_alloca
  17379. X#else
  17380. X#ifdef HAVE_ALLOCA_H
  17381. X#include <alloca.h>
  17382. X#else
  17383. X#ifdef _AIX /* for Bison */
  17384. X #pragma alloca
  17385. X#else
  17386. Xchar *alloca ();
  17387. X#endif
  17388. X#endif
  17389. X#endif
  17390. X
  17391. X#include <stdio.h>
  17392. X#include <ctype.h>
  17393. X
  17394. X/* The code at the top of get_date which figures out the offset of the
  17395. X   current time zone checks various CPP symbols to see if special
  17396. X   tricks are need, but defaults to using the gettimeofday system call.
  17397. X   Include <sys/time.h> if that will be used.  */
  17398. X
  17399. X#if !defined (USG) && !defined (sgi) && !defined (__386BSD__)
  17400. X#include <sys/time.h>
  17401. X#endif
  17402. X
  17403. X#if    defined(vms)
  17404. X
  17405. X#include <types.h>
  17406. X#include <time.h>
  17407. X
  17408. X#else
  17409. X
  17410. X#include <sys/types.h>
  17411. X
  17412. X#if    defined(USG) || !defined(HAVE_FTIME)
  17413. X/*
  17414. X**  If you need to do a tzset() call to set the
  17415. X**  timezone, and don't have ftime().
  17416. X*/
  17417. Xstruct timeb {
  17418. X    time_t        time;        /* Seconds since the epoch    */
  17419. X    unsigned short    millitm;    /* Field not used        */
  17420. X    short        timezone;
  17421. X    short        dstflag;    /* Field not used        */
  17422. X};
  17423. X
  17424. X#else
  17425. X
  17426. X#include <sys/timeb.h>
  17427. X
  17428. X#endif    /* defined(USG) && !defined(HAVE_FTIME) */
  17429. X
  17430. X#if    defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
  17431. X#include <sys/time.h>
  17432. X#else
  17433. X#if defined(_AIX)
  17434. X#include <sys/time.h>
  17435. X#endif
  17436. X#include <time.h>
  17437. X#endif    /* defined(BSD4_2) */
  17438. X
  17439. X#endif    /* defined(vms) */
  17440. X
  17441. X#if defined (STDC_HEADERS) || defined (USG)
  17442. X#include <string.h>
  17443. X#endif
  17444. X
  17445. X#if sgi
  17446. X#undef timezone
  17447. X#endif
  17448. X
  17449. Xextern struct tm    *localtime();
  17450. X
  17451. X#define yyparse getdate_yyparse
  17452. X#define yylex getdate_yylex
  17453. X#define yyerror getdate_yyerror
  17454. X
  17455. X#if    !defined(lint) && !defined(SABER)
  17456. Xstatic char RCS[] =
  17457. X    "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
  17458. X#endif    /* !defined(lint) && !defined(SABER) */
  17459. X
  17460. X
  17461. X#define EPOCH        1970
  17462. X#define HOUR(x)        ((time_t)(x) * 60)
  17463. X#define SECSPERDAY    (24L * 60L * 60L)
  17464. X
  17465. X
  17466. X/*
  17467. X**  An entry in the lexical lookup table.
  17468. X*/
  17469. Xtypedef struct _TABLE {
  17470. X    char    *name;
  17471. X    int        type;
  17472. X    time_t    value;
  17473. X} TABLE;
  17474. X
  17475. X
  17476. X/*
  17477. X**  Daylight-savings mode:  on, off, or not yet known.
  17478. X*/
  17479. Xtypedef enum _DSTMODE {
  17480. X    DSTon, DSToff, DSTmaybe
  17481. X} DSTMODE;
  17482. X
  17483. X/*
  17484. X**  Meridian:  am, pm, or 24-hour style.
  17485. X*/
  17486. Xtypedef enum _MERIDIAN {
  17487. X    MERam, MERpm, MER24
  17488. X} MERIDIAN;
  17489. X
  17490. X
  17491. X/*
  17492. X**  Global variables.  We could get rid of most of these by using a good
  17493. X**  union as the yacc stack.  (This routine was originally written before
  17494. X**  yacc had the %union construct.)  Maybe someday; right now we only use
  17495. X**  the %union very rarely.
  17496. X*/
  17497. Xstatic char    *yyInput;
  17498. Xstatic DSTMODE    yyDSTmode;
  17499. Xstatic time_t    yyDayOrdinal;
  17500. Xstatic time_t    yyDayNumber;
  17501. Xstatic int    yyHaveDate;
  17502. Xstatic int    yyHaveDay;
  17503. Xstatic int    yyHaveRel;
  17504. Xstatic int    yyHaveTime;
  17505. Xstatic int    yyHaveZone;
  17506. Xstatic time_t    yyTimezone;
  17507. Xstatic time_t    yyDay;
  17508. Xstatic time_t    yyHour;
  17509. Xstatic time_t    yyMinutes;
  17510. Xstatic time_t    yyMonth;
  17511. Xstatic time_t    yySeconds;
  17512. Xstatic time_t    yyYear;
  17513. Xstatic MERIDIAN    yyMeridian;
  17514. Xstatic time_t    yyRelMonth;
  17515. Xstatic time_t    yyRelSeconds;
  17516. X
  17517. X%}
  17518. X
  17519. X%union {
  17520. X    time_t        Number;
  17521. X    enum _MERIDIAN    Meridian;
  17522. X}
  17523. X
  17524. X%token    tAGO tDAY tDAYZONE tID tMERIDIAN tMINUTE_UNIT tMONTH tMONTH_UNIT
  17525. X%token    tSEC_UNIT tSNUMBER tUNUMBER tZONE tDST
  17526. X
  17527. X%type    <Number>    tDAY tDAYZONE tMINUTE_UNIT tMONTH tMONTH_UNIT
  17528. X%type    <Number>    tSEC_UNIT tSNUMBER tUNUMBER tZONE
  17529. X%type    <Meridian>    tMERIDIAN o_merid
  17530. X
  17531. X%%
  17532. X
  17533. Xspec    : /* NULL */
  17534. X    | spec item
  17535. X    ;
  17536. X
  17537. Xitem    : time {
  17538. X        yyHaveTime++;
  17539. X    }
  17540. X    | zone {
  17541. X        yyHaveZone++;
  17542. X    }
  17543. X    | date {
  17544. X        yyHaveDate++;
  17545. X    }
  17546. X    | day {
  17547. X        yyHaveDay++;
  17548. X    }
  17549. X    | rel {
  17550. X        yyHaveRel++;
  17551. X    }
  17552. X    | number
  17553. X    ;
  17554. X
  17555. Xtime    : tUNUMBER tMERIDIAN {
  17556. X        yyHour = $1;
  17557. X        yyMinutes = 0;
  17558. X        yySeconds = 0;
  17559. X        yyMeridian = $2;
  17560. X    }
  17561. X    | tUNUMBER ':' tUNUMBER o_merid {
  17562. X        yyHour = $1;
  17563. X        yyMinutes = $3;
  17564. X        yySeconds = 0;
  17565. X        yyMeridian = $4;
  17566. X    }
  17567. X    | tUNUMBER ':' tUNUMBER tSNUMBER {
  17568. X        yyHour = $1;
  17569. X        yyMinutes = $3;
  17570. X        yyMeridian = MER24;
  17571. X        yyDSTmode = DSToff;
  17572. X        yyTimezone = - ($4 % 100 + ($4 / 100) * 60);
  17573. X    }
  17574. X    | tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
  17575. X        yyHour = $1;
  17576. X        yyMinutes = $3;
  17577. X        yySeconds = $5;
  17578. X        yyMeridian = $6;
  17579. X    }
  17580. X    | tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
  17581. X        yyHour = $1;
  17582. X        yyMinutes = $3;
  17583. X        yySeconds = $5;
  17584. X        yyMeridian = MER24;
  17585. X        yyDSTmode = DSToff;
  17586. X        yyTimezone = - ($6 % 100 + ($6 / 100) * 60);
  17587. X    }
  17588. X    ;
  17589. X
  17590. Xzone    : tZONE {
  17591. X        yyTimezone = $1;
  17592. X        yyDSTmode = DSToff;
  17593. X    }
  17594. X    | tDAYZONE {
  17595. X        yyTimezone = $1;
  17596. X        yyDSTmode = DSTon;
  17597. X    }
  17598. X    |
  17599. X      tZONE tDST {
  17600. X        yyTimezone = $1;
  17601. X        yyDSTmode = DSTon;
  17602. X    }
  17603. X    ;
  17604. X
  17605. Xday    : tDAY {
  17606. X        yyDayOrdinal = 1;
  17607. X        yyDayNumber = $1;
  17608. X    }
  17609. X    | tDAY ',' {
  17610. X        yyDayOrdinal = 1;
  17611. X        yyDayNumber = $1;
  17612. X    }
  17613. X    | tUNUMBER tDAY {
  17614. X        yyDayOrdinal = $1;
  17615. X        yyDayNumber = $2;
  17616. X    }
  17617. X    ;
  17618. X
  17619. Xdate    : tUNUMBER '/' tUNUMBER {
  17620. X        yyMonth = $1;
  17621. X        yyDay = $3;
  17622. X    }
  17623. X    | tUNUMBER '/' tUNUMBER '/' tUNUMBER {
  17624. X        yyMonth = $1;
  17625. X        yyDay = $3;
  17626. X        yyYear = $5;
  17627. X    }
  17628. X    | tUNUMBER tSNUMBER tSNUMBER {
  17629. X        /* ISO 8601 format.  yyyy-mm-dd.  */
  17630. X        yyYear = $1;
  17631. X        yyMonth = -$2;
  17632. X        yyDay = -$3;
  17633. X    }
  17634. X    | tMONTH tUNUMBER {
  17635. X        yyMonth = $1;
  17636. X        yyDay = $2;
  17637. X    }
  17638. X    | tMONTH tUNUMBER ',' tUNUMBER {
  17639. X        yyMonth = $1;
  17640. X        yyDay = $2;
  17641. X        yyYear = $4;
  17642. X    }
  17643. X    | tUNUMBER tMONTH {
  17644. X        yyMonth = $2;
  17645. X        yyDay = $1;
  17646. X    }
  17647. X    | tUNUMBER tMONTH tUNUMBER {
  17648. X        yyMonth = $2;
  17649. X        yyDay = $1;
  17650. X        yyYear = $3;
  17651. X    }
  17652. X    ;
  17653. X
  17654. Xrel    : relunit tAGO {
  17655. X        yyRelSeconds = -yyRelSeconds;
  17656. X        yyRelMonth = -yyRelMonth;
  17657. X    }
  17658. X    | relunit
  17659. X    ;
  17660. X
  17661. Xrelunit    : tUNUMBER tMINUTE_UNIT {
  17662. X        yyRelSeconds += $1 * $2 * 60L;
  17663. X    }
  17664. X    | tSNUMBER tMINUTE_UNIT {
  17665. X        yyRelSeconds += $1 * $2 * 60L;
  17666. X    }
  17667. X    | tMINUTE_UNIT {
  17668. X        yyRelSeconds += $1 * 60L;
  17669. X    }
  17670. X    | tSNUMBER tSEC_UNIT {
  17671. X        yyRelSeconds += $1;
  17672. X    }
  17673. X    | tUNUMBER tSEC_UNIT {
  17674. X        yyRelSeconds += $1;
  17675. X    }
  17676. X    | tSEC_UNIT {
  17677. X        yyRelSeconds++;
  17678. X    }
  17679. X    | tSNUMBER tMONTH_UNIT {
  17680. X        yyRelMonth += $1 * $2;
  17681. X    }
  17682. X    | tUNUMBER tMONTH_UNIT {
  17683. X        yyRelMonth += $1 * $2;
  17684. X    }
  17685. X    | tMONTH_UNIT {
  17686. X        yyRelMonth += $1;
  17687. X    }
  17688. X    ;
  17689. X
  17690. Xnumber    : tUNUMBER {
  17691. X        if (yyHaveTime && yyHaveDate && !yyHaveRel)
  17692. X        yyYear = $1;
  17693. X        else {
  17694. X        if($1>10000) {
  17695. X            time_t date_part;
  17696. X
  17697. X            date_part= $1/10000;
  17698. X            yyHaveDate++;
  17699. X            yyDay= (date_part)%100;
  17700. X            yyMonth= (date_part/100)%100;
  17701. X            yyYear = date_part/10000;
  17702. X        } 
  17703. X            yyHaveTime++;
  17704. X        if ($1 < 100) {
  17705. X            yyHour = $1;
  17706. X            yyMinutes = 0;
  17707. X        }
  17708. X        else {
  17709. X            yyHour = $1 / 100;
  17710. X            yyMinutes = $1 % 100;
  17711. X        }
  17712. X        yySeconds = 0;
  17713. X        yyMeridian = MER24;
  17714. X        }
  17715. X    }
  17716. X    ;
  17717. X
  17718. Xo_merid    : /* NULL */ {
  17719. X        $$ = MER24;
  17720. X    }
  17721. X    | tMERIDIAN {
  17722. X        $$ = $1;
  17723. X    }
  17724. X    ;
  17725. X
  17726. X%%
  17727. X
  17728. X/* Month and day table. */
  17729. Xstatic TABLE const MonthDayTable[] = {
  17730. X    { "january",    tMONTH,  1 },
  17731. X    { "february",    tMONTH,  2 },
  17732. X    { "march",        tMONTH,  3 },
  17733. X    { "april",        tMONTH,  4 },
  17734. X    { "may",        tMONTH,  5 },
  17735. X    { "june",        tMONTH,  6 },
  17736. X    { "july",        tMONTH,  7 },
  17737. X    { "august",        tMONTH,  8 },
  17738. X    { "september",    tMONTH,  9 },
  17739. X    { "sept",        tMONTH,  9 },
  17740. X    { "october",    tMONTH, 10 },
  17741. X    { "november",    tMONTH, 11 },
  17742. X    { "december",    tMONTH, 12 },
  17743. X    { "sunday",        tDAY, 0 },
  17744. X    { "monday",        tDAY, 1 },
  17745. X    { "tuesday",    tDAY, 2 },
  17746. X    { "tues",        tDAY, 2 },
  17747. X    { "wednesday",    tDAY, 3 },
  17748. X    { "wednes",        tDAY, 3 },
  17749. X    { "thursday",    tDAY, 4 },
  17750. X    { "thur",        tDAY, 4 },
  17751. X    { "thurs",        tDAY, 4 },
  17752. X    { "friday",        tDAY, 5 },
  17753. X    { "saturday",    tDAY, 6 },
  17754. X    { NULL }
  17755. X};
  17756. X
  17757. X/* Time units table. */
  17758. Xstatic TABLE const UnitsTable[] = {
  17759. X    { "year",        tMONTH_UNIT,    12 },
  17760. X    { "month",        tMONTH_UNIT,    1 },
  17761. X    { "fortnight",    tMINUTE_UNIT,    14 * 24 * 60 },
  17762. X    { "week",        tMINUTE_UNIT,    7 * 24 * 60 },
  17763. X    { "day",        tMINUTE_UNIT,    1 * 24 * 60 },
  17764. X    { "hour",        tMINUTE_UNIT,    60 },
  17765. X    { "minute",        tMINUTE_UNIT,    1 },
  17766. X    { "min",        tMINUTE_UNIT,    1 },
  17767. X    { "second",        tSEC_UNIT,    1 },
  17768. X    { "sec",        tSEC_UNIT,    1 },
  17769. X    { NULL }
  17770. X};
  17771. X
  17772. X/* Assorted relative-time words. */
  17773. Xstatic TABLE const OtherTable[] = {
  17774. X    { "tomorrow",    tMINUTE_UNIT,    1 * 24 * 60 },
  17775. X    { "yesterday",    tMINUTE_UNIT,    -1 * 24 * 60 },
  17776. X    { "today",        tMINUTE_UNIT,    0 },
  17777. X    { "now",        tMINUTE_UNIT,    0 },
  17778. X    { "last",        tUNUMBER,    -1 },
  17779. X    { "this",        tMINUTE_UNIT,    0 },
  17780. X    { "next",        tUNUMBER,    2 },
  17781. X    { "first",        tUNUMBER,    1 },
  17782. X/*  { "second",        tUNUMBER,    2 }, */
  17783. X    { "third",        tUNUMBER,    3 },
  17784. X    { "fourth",        tUNUMBER,    4 },
  17785. X    { "fifth",        tUNUMBER,    5 },
  17786. X    { "sixth",        tUNUMBER,    6 },
  17787. X    { "seventh",    tUNUMBER,    7 },
  17788. X    { "eighth",        tUNUMBER,    8 },
  17789. X    { "ninth",        tUNUMBER,    9 },
  17790. X    { "tenth",        tUNUMBER,    10 },
  17791. X    { "eleventh",    tUNUMBER,    11 },
  17792. X    { "twelfth",    tUNUMBER,    12 },
  17793. X    { "ago",        tAGO,    1 },
  17794. X    { NULL }
  17795. X};
  17796. X
  17797. X/* The timezone table. */
  17798. X/* Some of these are commented out because a time_t can't store a float. */
  17799. Xstatic TABLE const TimezoneTable[] = {
  17800. X    { "gmt",    tZONE,     HOUR( 0) },    /* Greenwich Mean */
  17801. X    { "ut",    tZONE,     HOUR( 0) },    /* Universal (Coordinated) */
  17802. X    { "utc",    tZONE,     HOUR( 0) },
  17803. X    { "wet",    tZONE,     HOUR( 0) },    /* Western European */
  17804. X    { "bst",    tDAYZONE,  HOUR( 0) },    /* British Summer */
  17805. X    { "wat",    tZONE,     HOUR( 1) },    /* West Africa */
  17806. X    { "at",    tZONE,     HOUR( 2) },    /* Azores */
  17807. X#if    0
  17808. X    /* For completeness.  BST is also British Summer, and GST is
  17809. X     * also Guam Standard. */
  17810. X    { "bst",    tZONE,     HOUR( 3) },    /* Brazil Standard */
  17811. X    { "gst",    tZONE,     HOUR( 3) },    /* Greenland Standard */
  17812. X#endif
  17813. X#if 0
  17814. X    { "nft",    tZONE,     HOUR(3.5) },    /* Newfoundland */
  17815. X    { "nst",    tZONE,     HOUR(3.5) },    /* Newfoundland Standard */
  17816. X    { "ndt",    tDAYZONE,  HOUR(3.5) },    /* Newfoundland Daylight */
  17817. X#endif
  17818. X    { "ast",    tZONE,     HOUR( 4) },    /* Atlantic Standard */
  17819. X    { "adt",    tDAYZONE,  HOUR( 4) },    /* Atlantic Daylight */
  17820. X    { "est",    tZONE,     HOUR( 5) },    /* Eastern Standard */
  17821. X    { "edt",    tDAYZONE,  HOUR( 5) },    /* Eastern Daylight */
  17822. X    { "cst",    tZONE,     HOUR( 6) },    /* Central Standard */
  17823. X    { "cdt",    tDAYZONE,  HOUR( 6) },    /* Central Daylight */
  17824. X    { "mst",    tZONE,     HOUR( 7) },    /* Mountain Standard */
  17825. X    { "mdt",    tDAYZONE,  HOUR( 7) },    /* Mountain Daylight */
  17826. X    { "pst",    tZONE,     HOUR( 8) },    /* Pacific Standard */
  17827. X    { "pdt",    tDAYZONE,  HOUR( 8) },    /* Pacific Daylight */
  17828. X    { "yst",    tZONE,     HOUR( 9) },    /* Yukon Standard */
  17829. X    { "ydt",    tDAYZONE,  HOUR( 9) },    /* Yukon Daylight */
  17830. X    { "hst",    tZONE,     HOUR(10) },    /* Hawaii Standard */
  17831. X    { "hdt",    tDAYZONE,  HOUR(10) },    /* Hawaii Daylight */
  17832. X    { "cat",    tZONE,     HOUR(10) },    /* Central Alaska */
  17833. X    { "ahst",    tZONE,     HOUR(10) },    /* Alaska-Hawaii Standard */
  17834. X    { "nt",    tZONE,     HOUR(11) },    /* Nome */
  17835. X    { "idlw",    tZONE,     HOUR(12) },    /* International Date Line West */
  17836. X    { "cet",    tZONE,     -HOUR(1) },    /* Central European */
  17837. X    { "met",    tZONE,     -HOUR(1) },    /* Middle European */
  17838. X    { "mewt",    tZONE,     -HOUR(1) },    /* Middle European Winter */
  17839. X    { "mest",    tDAYZONE,  -HOUR(1) },    /* Middle European Summer */
  17840. X    { "swt",    tZONE,     -HOUR(1) },    /* Swedish Winter */
  17841. X    { "sst",    tDAYZONE,  -HOUR(1) },    /* Swedish Summer */
  17842. X    { "fwt",    tZONE,     -HOUR(1) },    /* French Winter */
  17843. X    { "fst",    tDAYZONE,  -HOUR(1) },    /* French Summer */
  17844. X    { "eet",    tZONE,     -HOUR(2) },    /* Eastern Europe, USSR Zone 1 */
  17845. X    { "bt",    tZONE,     -HOUR(3) },    /* Baghdad, USSR Zone 2 */
  17846. X#if 0
  17847. X    { "it",    tZONE,     -HOUR(3.5) },/* Iran */
  17848. X#endif
  17849. X    { "zp4",    tZONE,     -HOUR(4) },    /* USSR Zone 3 */
  17850. X    { "zp5",    tZONE,     -HOUR(5) },    /* USSR Zone 4 */
  17851. X#if 0
  17852. X    { "ist",    tZONE,     -HOUR(5.5) },/* Indian Standard */
  17853. X#endif
  17854. X    { "zp6",    tZONE,     -HOUR(6) },    /* USSR Zone 5 */
  17855. X#if    0
  17856. X    /* For completeness.  NST is also Newfoundland Stanard, and SST is
  17857. X     * also Swedish Summer. */
  17858. X    { "nst",    tZONE,     -HOUR(6.5) },/* North Sumatra */
  17859. X    { "sst",    tZONE,     -HOUR(7) },    /* South Sumatra, USSR Zone 6 */
  17860. X#endif    /* 0 */
  17861. X    { "wast",    tZONE,     -HOUR(7) },    /* West Australian Standard */
  17862. X    { "wadt",    tDAYZONE,  -HOUR(7) },    /* West Australian Daylight */
  17863. X#if 0
  17864. X    { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
  17865. X#endif
  17866. X    { "cct",    tZONE,     -HOUR(8) },    /* China Coast, USSR Zone 7 */
  17867. X    { "jst",    tZONE,     -HOUR(9) },    /* Japan Standard, USSR Zone 8 */
  17868. X#if 0
  17869. X    { "cast",    tZONE,     -HOUR(9.5) },/* Central Australian Standard */
  17870. X    { "cadt",    tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
  17871. X#endif
  17872. X    { "east",    tZONE,     -HOUR(10) },    /* Eastern Australian Standard */
  17873. X    { "eadt",    tDAYZONE,  -HOUR(10) },    /* Eastern Australian Daylight */
  17874. X    { "gst",    tZONE,     -HOUR(10) },    /* Guam Standard, USSR Zone 9 */
  17875. X    { "nzt",    tZONE,     -HOUR(12) },    /* New Zealand */
  17876. X    { "nzst",    tZONE,     -HOUR(12) },    /* New Zealand Standard */
  17877. X    { "nzdt",    tDAYZONE,  -HOUR(12) },    /* New Zealand Daylight */
  17878. X    { "idle",    tZONE,     -HOUR(12) },    /* International Date Line East */
  17879. X    {  NULL  }
  17880. X};
  17881. X
  17882. X/* Military timezone table. */
  17883. Xstatic TABLE const MilitaryTable[] = {
  17884. X    { "a",    tZONE,    HOUR(  1) },
  17885. X    { "b",    tZONE,    HOUR(  2) },
  17886. X    { "c",    tZONE,    HOUR(  3) },
  17887. X    { "d",    tZONE,    HOUR(  4) },
  17888. X    { "e",    tZONE,    HOUR(  5) },
  17889. X    { "f",    tZONE,    HOUR(  6) },
  17890. X    { "g",    tZONE,    HOUR(  7) },
  17891. X    { "h",    tZONE,    HOUR(  8) },
  17892. X    { "i",    tZONE,    HOUR(  9) },
  17893. X    { "k",    tZONE,    HOUR( 10) },
  17894. X    { "l",    tZONE,    HOUR( 11) },
  17895. X    { "m",    tZONE,    HOUR( 12) },
  17896. X    { "n",    tZONE,    HOUR(- 1) },
  17897. X    { "o",    tZONE,    HOUR(- 2) },
  17898. X    { "p",    tZONE,    HOUR(- 3) },
  17899. X    { "q",    tZONE,    HOUR(- 4) },
  17900. X    { "r",    tZONE,    HOUR(- 5) },
  17901. X    { "s",    tZONE,    HOUR(- 6) },
  17902. X    { "t",    tZONE,    HOUR(- 7) },
  17903. X    { "u",    tZONE,    HOUR(- 8) },
  17904. X    { "v",    tZONE,    HOUR(- 9) },
  17905. X    { "w",    tZONE,    HOUR(-10) },
  17906. X    { "x",    tZONE,    HOUR(-11) },
  17907. X    { "y",    tZONE,    HOUR(-12) },
  17908. X    { "z",    tZONE,    HOUR(  0) },
  17909. X    { NULL }
  17910. X};
  17911. X
  17912. X
  17913. X
  17914. X
  17915. X/* ARGSUSED */
  17916. Xstatic int
  17917. Xyyerror(s)
  17918. X    char    *s;
  17919. X{
  17920. X  return 0;
  17921. X}
  17922. X
  17923. X
  17924. Xstatic time_t
  17925. XToSeconds(Hours, Minutes, Seconds, Meridian)
  17926. X    time_t    Hours;
  17927. X    time_t    Minutes;
  17928. X    time_t    Seconds;
  17929. X    MERIDIAN    Meridian;
  17930. X{
  17931. X    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
  17932. X    return -1;
  17933. X    switch (Meridian) {
  17934. X    case MER24:
  17935. X    if (Hours < 0 || Hours > 23)
  17936. X        return -1;
  17937. X    return (Hours * 60L + Minutes) * 60L + Seconds;
  17938. X    case MERam:
  17939. X    if (Hours < 1 || Hours > 12)
  17940. X        return -1;
  17941. X    return (Hours * 60L + Minutes) * 60L + Seconds;
  17942. X    case MERpm:
  17943. X    if (Hours < 1 || Hours > 12)
  17944. X        return -1;
  17945. X    return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
  17946. X    }
  17947. X    /* NOTREACHED */
  17948. X}
  17949. X
  17950. X
  17951. Xstatic time_t
  17952. XConvert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
  17953. X    time_t    Month;
  17954. X    time_t    Day;
  17955. X    time_t    Year;
  17956. X    time_t    Hours;
  17957. X    time_t    Minutes;
  17958. X    time_t    Seconds;
  17959. X    MERIDIAN    Meridian;
  17960. X    DSTMODE    DSTmode;
  17961. X{
  17962. X    static int DaysInMonth[12] = {
  17963. X    31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  17964. X    };
  17965. X    time_t    tod;
  17966. X    time_t    Julian;
  17967. X    int        i;
  17968. X
  17969. X    if (Year < 0)
  17970. X    Year = -Year;
  17971. X    if (Year < 100)
  17972. X    Year += 1900;
  17973. X    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
  17974. X            ? 29 : 28;
  17975. X    if (Year < EPOCH || Year > 1999
  17976. X     || Month < 1 || Month > 12
  17977. X     /* Lint fluff:  "conversion from long may lose accuracy" */
  17978. X     || Day < 1 || Day > DaysInMonth[(int)--Month])
  17979. X    return -1;
  17980. X
  17981. X    for (Julian = Day - 1, i = 0; i < Month; i++)
  17982. X    Julian += DaysInMonth[i];
  17983. X    for (i = EPOCH; i < Year; i++)
  17984. X    Julian += 365 + (i % 4 == 0);
  17985. X    Julian *= SECSPERDAY;
  17986. X    Julian += yyTimezone * 60L;
  17987. X    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
  17988. X    return -1;
  17989. X    Julian += tod;
  17990. X    if (DSTmode == DSTon
  17991. X     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
  17992. X    Julian -= 60 * 60;
  17993. X    return Julian;
  17994. X}
  17995. X
  17996. X
  17997. Xstatic time_t
  17998. XDSTcorrect(Start, Future)
  17999. X    time_t    Start;
  18000. X    time_t    Future;
  18001. X{
  18002. X    time_t    StartDay;
  18003. X    time_t    FutureDay;
  18004. X
  18005. X    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
  18006. X    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
  18007. X    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
  18008. X}
  18009. X
  18010. X
  18011. Xstatic time_t
  18012. XRelativeDate(Start, DayOrdinal, DayNumber)
  18013. X    time_t    Start;
  18014. X    time_t    DayOrdinal;
  18015. X    time_t    DayNumber;
  18016. X{
  18017. X    struct tm    *tm;
  18018. X    time_t    now;
  18019. X
  18020. X    now = Start;
  18021. X    tm = localtime(&now);
  18022. X    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
  18023. X    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
  18024. X    return DSTcorrect(Start, now);
  18025. X}
  18026. X
  18027. X
  18028. Xstatic time_t
  18029. XRelativeMonth(Start, RelMonth)
  18030. X    time_t    Start;
  18031. X    time_t    RelMonth;
  18032. X{
  18033. X    struct tm    *tm;
  18034. X    time_t    Month;
  18035. X    time_t    Year;
  18036. X
  18037. X    if (RelMonth == 0)
  18038. X    return 0;
  18039. X    tm = localtime(&Start);
  18040. X    Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
  18041. X    Year = Month / 12;
  18042. X    Month = Month % 12 + 1;
  18043. X    return DSTcorrect(Start,
  18044. X        Convert(Month, (time_t)tm->tm_mday, Year,
  18045. X        (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
  18046. X        MER24, DSTmaybe));
  18047. X}
  18048. X
  18049. X
  18050. Xstatic int
  18051. XLookupWord(buff)
  18052. X    char        *buff;
  18053. X{
  18054. X    register char    *p;
  18055. X    register char    *q;
  18056. X    register const TABLE    *tp;
  18057. X    int            i;
  18058. X    int            abbrev;
  18059. X
  18060. X    /* Make it lowercase. */
  18061. X    for (p = buff; *p; p++)
  18062. X    if (isupper(*p))
  18063. X        *p = tolower(*p);
  18064. X
  18065. X    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
  18066. X    yylval.Meridian = MERam;
  18067. X    return tMERIDIAN;
  18068. X    }
  18069. X    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
  18070. X    yylval.Meridian = MERpm;
  18071. X    return tMERIDIAN;
  18072. X    }
  18073. X
  18074. X    /* See if we have an abbreviation for a month. */
  18075. X    if (strlen(buff) == 3)
  18076. X    abbrev = 1;
  18077. X    else if (strlen(buff) == 4 && buff[3] == '.') {
  18078. X    abbrev = 1;
  18079. X    buff[3] = '\0';
  18080. X    }
  18081. X    else
  18082. X    abbrev = 0;
  18083. X
  18084. X    for (tp = MonthDayTable; tp->name; tp++) {
  18085. X    if (abbrev) {
  18086. X        if (strncmp(buff, tp->name, 3) == 0) {
  18087. X        yylval.Number = tp->value;
  18088. X        return tp->type;
  18089. X        }
  18090. X    }
  18091. X    else if (strcmp(buff, tp->name) == 0) {
  18092. X        yylval.Number = tp->value;
  18093. X        return tp->type;
  18094. X    }
  18095. X    }
  18096. X
  18097. X    for (tp = TimezoneTable; tp->name; tp++)
  18098. X    if (strcmp(buff, tp->name) == 0) {
  18099. X        yylval.Number = tp->value;
  18100. X        return tp->type;
  18101. X    }
  18102. X
  18103. X    if (strcmp(buff, "dst") == 0) 
  18104. X    return tDST;
  18105. X
  18106. X    for (tp = UnitsTable; tp->name; tp++)
  18107. X    if (strcmp(buff, tp->name) == 0) {
  18108. X        yylval.Number = tp->value;
  18109. X        return tp->type;
  18110. X    }
  18111. X
  18112. X    /* Strip off any plural and try the units table again. */
  18113. X    i = strlen(buff) - 1;
  18114. X    if (buff[i] == 's') {
  18115. X    buff[i] = '\0';
  18116. X    for (tp = UnitsTable; tp->name; tp++)
  18117. X        if (strcmp(buff, tp->name) == 0) {
  18118. X        yylval.Number = tp->value;
  18119. X        return tp->type;
  18120. X        }
  18121. X    buff[i] = 's';        /* Put back for "this" in OtherTable. */
  18122. X    }
  18123. X
  18124. X    for (tp = OtherTable; tp->name; tp++)
  18125. X    if (strcmp(buff, tp->name) == 0) {
  18126. X        yylval.Number = tp->value;
  18127. X        return tp->type;
  18128. X    }
  18129. X
  18130. X    /* Military timezones. */
  18131. X    if (buff[1] == '\0' && isalpha(*buff)) {
  18132. X    for (tp = MilitaryTable; tp->name; tp++)
  18133. X        if (strcmp(buff, tp->name) == 0) {
  18134. X        yylval.Number = tp->value;
  18135. X        return tp->type;
  18136. X        }
  18137. X    }
  18138. X
  18139. X    /* Drop out any periods and try the timezone table again. */
  18140. X    for (i = 0, p = q = buff; *q; q++)
  18141. X    if (*q != '.')
  18142. X        *p++ = *q;
  18143. X    else
  18144. X        i++;
  18145. X    *p = '\0';
  18146. X    if (i)
  18147. X    for (tp = TimezoneTable; tp->name; tp++)
  18148. X        if (strcmp(buff, tp->name) == 0) {
  18149. X        yylval.Number = tp->value;
  18150. X        return tp->type;
  18151. X        }
  18152. X
  18153. X    return tID;
  18154. X}
  18155. X
  18156. X
  18157. Xstatic int
  18158. Xyylex()
  18159. X{
  18160. X    register char    c;
  18161. X    register char    *p;
  18162. X    char        buff[20];
  18163. X    int            Count;
  18164. X    int            sign;
  18165. X
  18166. X    for ( ; ; ) {
  18167. X    while (isspace(*yyInput))
  18168. X        yyInput++;
  18169. X
  18170. X    if (isdigit(c = *yyInput) || c == '-' || c == '+') {
  18171. X        if (c == '-' || c == '+') {
  18172. X        sign = c == '-' ? -1 : 1;
  18173. X        if (!isdigit(*++yyInput))
  18174. X            /* skip the '-' sign */
  18175. X            continue;
  18176. X        }
  18177. X        else
  18178. X        sign = 0;
  18179. X        for (yylval.Number = 0; isdigit(c = *yyInput++); )
  18180. X        yylval.Number = 10 * yylval.Number + c - '0';
  18181. X        yyInput--;
  18182. X        if (sign < 0)
  18183. X        yylval.Number = -yylval.Number;
  18184. X        return sign ? tSNUMBER : tUNUMBER;
  18185. X    }
  18186. X    if (isalpha(c)) {
  18187. X        for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
  18188. X        if (p < &buff[sizeof buff - 1])
  18189. X            *p++ = c;
  18190. X        *p = '\0';
  18191. X        yyInput--;
  18192. X        return LookupWord(buff);
  18193. X    }
  18194. X    if (c != '(')
  18195. X        return *yyInput++;
  18196. X    Count = 0;
  18197. X    do {
  18198. X        c = *yyInput++;
  18199. X        if (c == '\0')
  18200. X        return c;
  18201. X        if (c == '(')
  18202. X        Count++;
  18203. X        else if (c == ')')
  18204. X        Count--;
  18205. X    } while (Count > 0);
  18206. X    }
  18207. X}
  18208. X
  18209. X
  18210. Xtime_t
  18211. Xget_date(p, now)
  18212. X    char        *p;
  18213. X    struct timeb    *now;
  18214. X{
  18215. X    struct tm        *tm;
  18216. X    struct timeb    ftz;
  18217. X    time_t        Start;
  18218. X    time_t        tod;
  18219. X
  18220. X    yyInput = p;
  18221. X    if (now == NULL) {
  18222. X        now = &ftz;
  18223. X#if    !defined(HAVE_FTIME)
  18224. X    (void)time(&ftz.time);
  18225. X    /* Set the timezone global. */
  18226. X    tzset();
  18227. X    {
  18228. X#if sgi
  18229. X        ftz.timezone = (int) _timezone / 60;
  18230. X#else /* not sgi */
  18231. X#ifdef __386BSD__
  18232. X        ftz.timezone = 0;
  18233. X#else /* neither sgi nor 386BSD */
  18234. X#if defined (USG)
  18235. X        extern time_t timezone;
  18236. X
  18237. X        ftz.timezone = (int) timezone / 60;
  18238. X#else /* neither sgi nor 386BSD nor USG */
  18239. X        struct timeval tv;
  18240. X        struct timezone tz;
  18241. X
  18242. X        gettimeofday (&tv, &tz);
  18243. X        ftz.timezone = (int) tz.tz_minuteswest;
  18244. X#endif /* neither sgi nor 386BSD nor USG */
  18245. X#endif /* neither sgi nor 386BSD */
  18246. X#endif /* not sgi */
  18247. X    }
  18248. X#else /* HAVE_FTIME */
  18249. X    (void)ftime(&ftz);
  18250. X#endif /* HAVE_FTIME */
  18251. X    }
  18252. X
  18253. X    tm = localtime(&now->time);
  18254. X    yyYear = tm->tm_year;
  18255. X    yyMonth = tm->tm_mon + 1;
  18256. X    yyDay = tm->tm_mday;
  18257. X    yyTimezone = now->timezone;
  18258. X    yyDSTmode = DSTmaybe;
  18259. X    yyHour = 0;
  18260. X    yyMinutes = 0;
  18261. X    yySeconds = 0;
  18262. X    yyMeridian = MER24;
  18263. X    yyRelSeconds = 0;
  18264. X    yyRelMonth = 0;
  18265. X    yyHaveDate = 0;
  18266. X    yyHaveDay = 0;
  18267. X    yyHaveRel = 0;
  18268. X    yyHaveTime = 0;
  18269. X    yyHaveZone = 0;
  18270. X
  18271. X    if (yyparse()
  18272. X     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
  18273. X    return -1;
  18274. X
  18275. X    if (yyHaveDate || yyHaveTime || yyHaveDay) {
  18276. X    Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  18277. X            yyMeridian, yyDSTmode);
  18278. X    if (Start < 0)
  18279. X        return -1;
  18280. X    }
  18281. X    else {
  18282. X    Start = now->time;
  18283. X    if (!yyHaveRel)
  18284. X        Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
  18285. X    }
  18286. X
  18287. X    Start += yyRelSeconds;
  18288. X    Start += RelativeMonth(Start, yyRelMonth);
  18289. X
  18290. X    if (yyHaveDay && !yyHaveDate) {
  18291. X    tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
  18292. X    Start += tod;
  18293. X    }
  18294. X
  18295. X    /* Have to do *something* with a legitimate -1 so it's distinguishable
  18296. X     * from the error return value.  (Alternately could set errno on error.) */
  18297. X    return Start == -1 ? 0 : Start;
  18298. X}
  18299. X
  18300. X
  18301. X#if    defined(TEST)
  18302. X
  18303. X/* ARGSUSED */
  18304. Xmain(ac, av)
  18305. X    int        ac;
  18306. X    char    *av[];
  18307. X{
  18308. X    char    buff[128];
  18309. X    time_t    d;
  18310. X
  18311. X    (void)printf("Enter date, or blank line to exit.\n\t> ");
  18312. X    (void)fflush(stdout);
  18313. X    while (gets(buff) && buff[0]) {
  18314. X    d = get_date(buff, (struct timeb *)NULL);
  18315. X    if (d == -1)
  18316. X        (void)printf("Bad format - couldn't convert.\n");
  18317. X    else
  18318. X        (void)printf("%s", ctime(&d));
  18319. X    (void)printf("\t> ");
  18320. X    (void)fflush(stdout);
  18321. X    }
  18322. X    exit(0);
  18323. X    /* NOTREACHED */
  18324. X}
  18325. X#endif    /* defined(TEST) */
  18326. END_OF_FILE
  18327. if test 22885 -ne `wc -c <'getdate.y'`; then
  18328.     echo shar: \"'getdate.y'\" unpacked with wrong size!
  18329. fi
  18330. # end of 'getdate.y'
  18331. fi
  18332. if test -f 'getdate.c' -a "${1}" != "-c" ; then 
  18333.   echo shar: Will not clobber existing file \"'getdate.c'\"
  18334. else
  18335. echo shar: Extracting \"'getdate.c'\" \(46681 characters\)
  18336. sed "s/^X//" >'getdate.c' <<'END_OF_FILE'
  18337. X
  18338. X/*  A Bison parser, made from ./getdate.y  */
  18339. X
  18340. X#define YYBISON 1  /* Identify Bison output.  */
  18341. X
  18342. X#define    tAGO    258
  18343. X#define    tDAY    259
  18344. X#define    tDAYZONE    260
  18345. X#define    tID    261
  18346. X#define    tMERIDIAN    262
  18347. X#define    tMINUTE_UNIT    263
  18348. X#define    tMONTH    264
  18349. X#define    tMONTH_UNIT    265
  18350. X#define    tSEC_UNIT    266
  18351. X#define    tSNUMBER    267
  18352. X#define    tUNUMBER    268
  18353. X#define    tZONE    269
  18354. X#define    tDST    270
  18355. X
  18356. X#line 1 "./getdate.y"
  18357. X
  18358. X/* $Revision: 2.1 $
  18359. X**
  18360. X**  Originally written by Steven M. Bellovin <smb@research.att.com> while
  18361. X**  at the University of North Carolina at Chapel Hill.  Later tweaked by
  18362. X**  a couple of people on Usenet.  Completely overhauled by Rich $alz
  18363. X**  <rsalz@bbn.com> and Jim Berets <jberets@bbn.com> in August, 1990;
  18364. X**  send any email to Rich.
  18365. X**
  18366. X**  This grammar has eight shift/reduce conflicts.
  18367. X**
  18368. X**  This code is in the public domain and has no copyright.
  18369. X*/
  18370. X/* SUPPRESS 287 on yaccpar_sccsid *//* Unusd static variable */
  18371. X/* SUPPRESS 288 on yyerrlab *//* Label unused */
  18372. X
  18373. X#ifdef HAVE_CONFIG_H
  18374. X#include "config.h"
  18375. X#endif
  18376. X
  18377. X#ifdef __GNUC__
  18378. X#define alloca __builtin_alloca
  18379. X#else
  18380. X#ifdef HAVE_ALLOCA_H
  18381. X#include <alloca.h>
  18382. X#else
  18383. X#ifdef _AIX /* for Bison */
  18384. X #pragma alloca
  18385. X#else
  18386. Xchar *alloca ();
  18387. X#endif
  18388. X#endif
  18389. X#endif
  18390. X
  18391. X#include <stdio.h>
  18392. X#include <ctype.h>
  18393. X
  18394. X/* The code at the top of get_date which figures out the offset of the
  18395. X   current time zone checks various CPP symbols to see if special
  18396. X   tricks are need, but defaults to using the gettimeofday system call.
  18397. X   Include <sys/time.h> if that will be used.  */
  18398. X
  18399. X#if !defined (USG) && !defined (sgi) && !defined (__386BSD__)
  18400. X#include <sys/time.h>
  18401. X#endif
  18402. X
  18403. X#if    defined(vms)
  18404. X
  18405. X#include <types.h>
  18406. X#include <time.h>
  18407. X
  18408. X#else
  18409. X
  18410. X#include <sys/types.h>
  18411. X
  18412. X#if    defined(USG) || !defined(HAVE_FTIME)
  18413. X/*
  18414. X**  If you need to do a tzset() call to set the
  18415. X**  timezone, and don't have ftime().
  18416. X*/
  18417. Xstruct timeb {
  18418. X    time_t        time;        /* Seconds since the epoch    */
  18419. X    unsigned short    millitm;    /* Field not used        */
  18420. X    short        timezone;
  18421. X    short        dstflag;    /* Field not used        */
  18422. X};
  18423. X
  18424. X#else
  18425. X
  18426. X#include <sys/timeb.h>
  18427. X
  18428. X#endif    /* defined(USG) && !defined(HAVE_FTIME) */
  18429. X
  18430. X#if    defined(BSD4_2) || defined(BSD4_1C) || (defined (hp9000) && !defined (hpux))
  18431. X#include <sys/time.h>
  18432. X#else
  18433. X#if defined(_AIX)
  18434. X#include <sys/time.h>
  18435. X#endif
  18436. X#include <time.h>
  18437. X#endif    /* defined(BSD4_2) */
  18438. X
  18439. X#endif    /* defined(vms) */
  18440. X
  18441. X#if defined (STDC_HEADERS) || defined (USG)
  18442. X#include <string.h>
  18443. X#endif
  18444. X
  18445. X#if sgi
  18446. X#undef timezone
  18447. X#endif
  18448. X
  18449. Xextern struct tm    *localtime();
  18450. X
  18451. X#define yyparse getdate_yyparse
  18452. X#define yylex getdate_yylex
  18453. X#define yyerror getdate_yyerror
  18454. X
  18455. X#if    !defined(lint) && !defined(SABER)
  18456. Xstatic char RCS[] =
  18457. X    "$Header: str2date.y,v 2.1 90/09/06 08:15:06 cronan Exp $";
  18458. X#endif    /* !defined(lint) && !defined(SABER) */
  18459. X
  18460. X
  18461. X#define EPOCH        1970
  18462. X#define HOUR(x)        ((time_t)(x) * 60)
  18463. X#define SECSPERDAY    (24L * 60L * 60L)
  18464. X
  18465. X
  18466. X/*
  18467. X**  An entry in the lexical lookup table.
  18468. X*/
  18469. Xtypedef struct _TABLE {
  18470. X    char    *name;
  18471. X    int        type;
  18472. X    time_t    value;
  18473. X} TABLE;
  18474. X
  18475. X
  18476. X/*
  18477. X**  Daylight-savings mode:  on, off, or not yet known.
  18478. X*/
  18479. Xtypedef enum _DSTMODE {
  18480. X    DSTon, DSToff, DSTmaybe
  18481. X} DSTMODE;
  18482. X
  18483. X/*
  18484. X**  Meridian:  am, pm, or 24-hour style.
  18485. X*/
  18486. Xtypedef enum _MERIDIAN {
  18487. X    MERam, MERpm, MER24
  18488. X} MERIDIAN;
  18489. X
  18490. X
  18491. X/*
  18492. X**  Global variables.  We could get rid of most of these by using a good
  18493. X**  union as the yacc stack.  (This routine was originally written before
  18494. X**  yacc had the %union construct.)  Maybe someday; right now we only use
  18495. X**  the %union very rarely.
  18496. X*/
  18497. Xstatic char    *yyInput;
  18498. Xstatic DSTMODE    yyDSTmode;
  18499. Xstatic time_t    yyDayOrdinal;
  18500. Xstatic time_t    yyDayNumber;
  18501. Xstatic int    yyHaveDate;
  18502. Xstatic int    yyHaveDay;
  18503. Xstatic int    yyHaveRel;
  18504. Xstatic int    yyHaveTime;
  18505. Xstatic int    yyHaveZone;
  18506. Xstatic time_t    yyTimezone;
  18507. Xstatic time_t    yyDay;
  18508. Xstatic time_t    yyHour;
  18509. Xstatic time_t    yyMinutes;
  18510. Xstatic time_t    yyMonth;
  18511. Xstatic time_t    yySeconds;
  18512. Xstatic time_t    yyYear;
  18513. Xstatic MERIDIAN    yyMeridian;
  18514. Xstatic time_t    yyRelMonth;
  18515. Xstatic time_t    yyRelSeconds;
  18516. X
  18517. X
  18518. X#line 163 "./getdate.y"
  18519. Xtypedef union {
  18520. X    time_t        Number;
  18521. X    enum _MERIDIAN    Meridian;
  18522. X} YYSTYPE;
  18523. X
  18524. X#ifndef YYLTYPE
  18525. Xtypedef
  18526. X  struct yyltype
  18527. X    {
  18528. X      int timestamp;
  18529. X      int first_line;
  18530. X      int first_column;
  18531. X      int last_line;
  18532. X      int last_column;
  18533. X      char *text;
  18534. X   }
  18535. X  yyltype;
  18536. X
  18537. X#define YYLTYPE yyltype
  18538. X#endif
  18539. X
  18540. X#include <stdio.h>
  18541. X
  18542. X#ifndef __STDC__
  18543. X#define const
  18544. X#endif
  18545. X
  18546. X
  18547. X
  18548. X#define    YYFINAL        51
  18549. X#define    YYFLAG        -32768
  18550. X#define    YYNTBASE    19
  18551. X
  18552. X#define YYTRANSLATE(x) ((unsigned)(x) <= 270 ? yytranslate[x] : 29)
  18553. X
  18554. Xstatic const char yytranslate[] = {     0,
  18555. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18556. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18557. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18558. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18559. X     2,     2,     2,    17,     2,     2,    18,     2,     2,     2,
  18560. X     2,     2,     2,     2,     2,     2,     2,    16,     2,     2,
  18561. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18562. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18563. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18564. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18565. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18566. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18567. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18568. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18569. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18570. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18571. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18572. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18573. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18574. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18575. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18576. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18577. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18578. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18579. X     2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
  18580. X     2,     2,     2,     2,     2,     1,     2,     3,     4,     5,
  18581. X     6,     7,     8,     9,    10,    11,    12,    13,    14,    15
  18582. X};
  18583. X
  18584. Xstatic const short yyprhs[] = {     0,
  18585. X     0,     1,     4,     6,     8,    10,    12,    14,    16,    19,
  18586. X    24,    29,    36,    43,    45,    47,    50,    52,    55,    58,
  18587. X    62,    68,    72,    75,    80,    83,    87,    90,    92,    95,
  18588. X    98,   100,   103,   106,   108,   111,   114,   116,   118,   119
  18589. X};
  18590. X
  18591. Xstatic const short yyrhs[] = {    -1,
  18592. X    19,    20,     0,    21,     0,    22,     0,    24,     0,    23,
  18593. X     0,    25,     0,    27,     0,    13,     7,     0,    13,    16,
  18594. X    13,    28,     0,    13,    16,    13,    12,     0,    13,    16,
  18595. X    13,    16,    13,    28,     0,    13,    16,    13,    16,    13,
  18596. X    12,     0,    14,     0,     5,     0,    14,    15,     0,     4,
  18597. X     0,     4,    17,     0,    13,     4,     0,    13,    18,    13,
  18598. X     0,    13,    18,    13,    18,    13,     0,    13,    12,    12,
  18599. X     0,     9,    13,     0,     9,    13,    17,    13,     0,    13,
  18600. X     9,     0,    13,     9,    13,     0,    26,     3,     0,    26,
  18601. X     0,    13,     8,     0,    12,     8,     0,     8,     0,    12,
  18602. X    11,     0,    13,    11,     0,    11,     0,    12,    10,     0,
  18603. X    13,    10,     0,    10,     0,    13,     0,     0,     7,     0
  18604. X};
  18605. X
  18606. X#if YYDEBUG != 0
  18607. Xstatic const short yyrline[] = { 0,
  18608. X   177,   178,   181,   184,   187,   190,   193,   196,   199,   205,
  18609. X   211,   218,   224,   234,   238,   242,   249,   253,   257,   263,
  18610. X   267,   272,   278,   282,   287,   291,   298,   302,   305,   308,
  18611. X   311,   314,   317,   320,   323,   326,   329,   334,   362,   365
  18612. X};
  18613. X
  18614. Xstatic const char * const yytname[] = {   "$","error","$illegal.","tAGO","tDAY",
  18615. X"tDAYZONE","tID","tMERIDIAN","tMINUTE_UNIT","tMONTH","tMONTH_UNIT","tSEC_UNIT",
  18616. X"tSNUMBER","tUNUMBER","tZONE","tDST","':'","','","'/'","spec","item","time",
  18617. X"zone","day","date","rel","relunit","number","o_merid",""
  18618. X};
  18619. X#endif
  18620. X
  18621. Xstatic const short yyr1[] = {     0,
  18622. X    19,    19,    20,    20,    20,    20,    20,    20,    21,    21,
  18623. X    21,    21,    21,    22,    22,    22,    23,    23,    23,    24,
  18624. X    24,    24,    24,    24,    24,    24,    25,    25,    26,    26,
  18625. X    26,    26,    26,    26,    26,    26,    26,    27,    28,    28
  18626. X};
  18627. X
  18628. Xstatic const short yyr2[] = {     0,
  18629. X     0,     2,     1,     1,     1,     1,     1,     1,     2,     4,
  18630. X     4,     6,     6,     1,     1,     2,     1,     2,     2,     3,
  18631. X     5,     3,     2,     4,     2,     3,     2,     1,     2,     2,
  18632. X     1,     2,     2,     1,     2,     2,     1,     1,     0,     1
  18633. X};
  18634. X
  18635. Xstatic const short yydefact[] = {     1,
  18636. X     0,    17,    15,    31,     0,    37,    34,     0,    38,    14,
  18637. X     2,     3,     4,     6,     5,     7,    28,     8,    18,    23,
  18638. X    30,    35,    32,    19,     9,    29,    25,    36,    33,     0,
  18639. X     0,     0,    16,    27,     0,    26,    22,    39,    20,    24,
  18640. X    40,    11,     0,    10,     0,    39,    21,    13,    12,     0,
  18641. X     0
  18642. X};
  18643. X
  18644. Xstatic const short yydefgoto[] = {     1,
  18645. X    11,    12,    13,    14,    15,    16,    17,    18,    44
  18646. X};
  18647. X
  18648. Xstatic const short yypact[] = {-32768,
  18649. X     0,   -15,-32768,-32768,   -10,-32768,-32768,    25,    11,    -8,
  18650. X-32768,-32768,-32768,-32768,-32768,-32768,    13,-32768,-32768,     7,
  18651. X-32768,-32768,-32768,-32768,-32768,-32768,     4,-32768,-32768,    14,
  18652. X    15,    19,-32768,-32768,    24,-32768,-32768,    18,    20,-32768,
  18653. X-32768,-32768,    26,-32768,    27,    -6,-32768,-32768,-32768,    31,
  18654. X-32768
  18655. X};
  18656. X
  18657. Xstatic const short yypgoto[] = {-32768,
  18658. X-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768,    -5
  18659. X};
  18660. X
  18661. X
  18662. X#define    YYLAST        41
  18663. X
  18664. X
  18665. Xstatic const short yytable[] = {    50,
  18666. X    41,    19,    20,     2,     3,    48,    33,     4,     5,     6,
  18667. X     7,     8,     9,    10,    24,    34,    36,    25,    26,    27,
  18668. X    28,    29,    30,    35,    41,    37,    31,    38,    32,    42,
  18669. X    51,    39,    21,    43,    22,    23,    40,    45,    46,    47,
  18670. X    49
  18671. X};
  18672. X
  18673. Xstatic const short yycheck[] = {     0,
  18674. X     7,    17,    13,     4,     5,    12,    15,     8,     9,    10,
  18675. X    11,    12,    13,    14,     4,     3,    13,     7,     8,     9,
  18676. X    10,    11,    12,    17,     7,    12,    16,    13,    18,    12,
  18677. X     0,    13,     8,    16,    10,    11,    13,    18,    13,    13,
  18678. X    46
  18679. X};
  18680. X/* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */
  18681. X#line 3 "bison.simple"
  18682. X
  18683. X/* Skeleton output parser for bison,
  18684. X   Copyright (C) 1984, 1989, 1990 Bob Corbett and Richard Stallman
  18685. X
  18686. X   This program is free software; you can redistribute it and/or modify
  18687. X   it under the terms of the GNU General Public License as published by
  18688. X   the Free Software Foundation; either version 1, or (at your option)
  18689. X   any later version.
  18690. X
  18691. X   This program is distributed in the hope that it will be useful,
  18692. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  18693. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18694. X   GNU General Public License for more details.
  18695. X
  18696. X   You should have received a copy of the GNU General Public License
  18697. X   along with this program; if not, write to the Free Software
  18698. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  18699. X
  18700. X
  18701. X#ifndef alloca
  18702. X#ifdef __GNUC__
  18703. X#define alloca __builtin_alloca
  18704. X#else /* not GNU C.  */
  18705. X#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__)
  18706. X#include <alloca.h>
  18707. X#else /* not sparc */
  18708. X#if defined (MSDOS) && !defined (__TURBOC__)
  18709. X#include <malloc.h>
  18710. X#else /* not MSDOS, or __TURBOC__ */
  18711. X#if defined(_AIX)
  18712. X#include <malloc.h>
  18713. X #pragma alloca
  18714. X#endif /* not _AIX */
  18715. X#endif /* not MSDOS, or __TURBOC__ */
  18716. X#endif /* not sparc.  */
  18717. X#endif /* not GNU C.  */
  18718. X#endif /* alloca not defined.  */
  18719. X
  18720. X/* This is the parser code that is written into each bison parser
  18721. X  when the %semantic_parser declaration is not specified in the grammar.
  18722. X  It was written by Richard Stallman by simplifying the hairy parser
  18723. X  used when %semantic_parser is specified.  */
  18724. X
  18725. X/* Note: there must be only one dollar sign in this file.
  18726. X   It is replaced by the list of actions, each action
  18727. X   as one case of the switch.  */
  18728. X
  18729. X#define yyerrok        (yyerrstatus = 0)
  18730. X#define yyclearin    (yychar = YYEMPTY)
  18731. X#define YYEMPTY        -2
  18732. X#define YYEOF        0
  18733. X#define YYACCEPT    return(0)
  18734. X#define YYABORT     return(1)
  18735. X#define YYERROR        goto yyerrlab1
  18736. X/* Like YYERROR except do call yyerror.
  18737. X   This remains here temporarily to ease the
  18738. X   transition to the new meaning of YYERROR, for GCC.
  18739. X   Once GCC version 2 has supplanted version 1, this can go.  */
  18740. X#define YYFAIL        goto yyerrlab
  18741. X#define YYRECOVERING()  (!!yyerrstatus)
  18742. X#define YYBACKUP(token, value) \
  18743. Xdo                                \
  18744. X  if (yychar == YYEMPTY && yylen == 1)                \
  18745. X    { yychar = (token), yylval = (value);            \
  18746. X      yychar1 = YYTRANSLATE (yychar);                \
  18747. X      YYPOPSTACK;                        \
  18748. X      goto yybackup;                        \
  18749. X    }                                \
  18750. X  else                                \
  18751. X    { yyerror ("syntax error: cannot back up"); YYERROR; }    \
  18752. Xwhile (0)
  18753. X
  18754. X#define YYTERROR    1
  18755. X#define YYERRCODE    256
  18756. X
  18757. X#ifndef YYPURE
  18758. X#define YYLEX        yylex()
  18759. X#endif
  18760. X
  18761. X#ifdef YYPURE
  18762. X#ifdef YYLSP_NEEDED
  18763. X#define YYLEX        yylex(&yylval, &yylloc)
  18764. X#else
  18765. X#define YYLEX        yylex(&yylval)
  18766. X#endif
  18767. X#endif
  18768. X
  18769. X/* If nonreentrant, generate the variables here */
  18770. X
  18771. X#ifndef YYPURE
  18772. X
  18773. Xint    yychar;            /*  the lookahead symbol        */
  18774. XYYSTYPE    yylval;            /*  the semantic value of the        */
  18775. X                /*  lookahead symbol            */
  18776. X
  18777. X#ifdef YYLSP_NEEDED
  18778. XYYLTYPE yylloc;            /*  location data for the lookahead    */
  18779. X                /*  symbol                */
  18780. X#endif
  18781. X
  18782. Xint yynerrs;            /*  number of parse errors so far       */
  18783. X#endif  /* not YYPURE */
  18784. X
  18785. X#if YYDEBUG != 0
  18786. Xint yydebug;            /*  nonzero means print parse trace    */
  18787. X/* Since this is uninitialized, it does not stop multiple parsers
  18788. X   from coexisting.  */
  18789. X#endif
  18790. X
  18791. X/*  YYINITDEPTH indicates the initial size of the parser's stacks    */
  18792. X
  18793. X#ifndef    YYINITDEPTH
  18794. X#define YYINITDEPTH 200
  18795. X#endif
  18796. X
  18797. X/*  YYMAXDEPTH is the maximum size the stacks can grow to
  18798. X    (effective only if the built-in stack extension method is used).  */
  18799. X
  18800. X#if YYMAXDEPTH == 0
  18801. X#undef YYMAXDEPTH
  18802. X#endif
  18803. X
  18804. X#ifndef YYMAXDEPTH
  18805. X#define YYMAXDEPTH 10000
  18806. X#endif
  18807. X
  18808. X#if __GNUC__ > 1        /* GNU C and GNU C++ define this.  */
  18809. X#define __yy_bcopy(FROM,TO,COUNT)    __builtin_memcpy(TO,FROM,COUNT)
  18810. X#else                /* not GNU C or C++ */
  18811. X#ifndef __cplusplus
  18812. X
  18813. X/* This is the most reliable way to avoid incompatibilities
  18814. X   in available built-in functions on various systems.  */
  18815. Xstatic void
  18816. X__yy_bcopy (from, to, count)
  18817. X     char *from;
  18818. X     char *to;
  18819. X     int count;
  18820. X{
  18821. X  register char *f = from;
  18822. X  register char *t = to;
  18823. X  register int i = count;
  18824. X
  18825. X  while (i-- > 0)
  18826. X    *t++ = *f++;
  18827. X}
  18828. X
  18829. X#else /* __cplusplus */
  18830. X
  18831. X/* This is the most reliable way to avoid incompatibilities
  18832. X   in available built-in functions on various systems.  */
  18833. Xstatic void
  18834. X__yy_bcopy (char *from, char *to, int count)
  18835. X{
  18836. X  register char *f = from;
  18837. X  register char *t = to;
  18838. X  register int i = count;
  18839. X
  18840. X  while (i-- > 0)
  18841. X    *t++ = *f++;
  18842. X}
  18843. X
  18844. X#endif
  18845. X#endif
  18846. X
  18847. X#line 169 "bison.simple"
  18848. Xint
  18849. Xyyparse()
  18850. X{
  18851. X  register int yystate;
  18852. X  register int yyn;
  18853. X  register short *yyssp;
  18854. X  register YYSTYPE *yyvsp;
  18855. X  int yyerrstatus;    /*  number of tokens to shift before error messages enabled */
  18856. X  int yychar1;        /*  lookahead token as an internal (translated) token number */
  18857. X
  18858. X  short    yyssa[YYINITDEPTH];    /*  the state stack            */
  18859. X  YYSTYPE yyvsa[YYINITDEPTH];    /*  the semantic value stack        */
  18860. X
  18861. X  short *yyss = yyssa;        /*  refer to the stacks thru separate pointers */
  18862. X  YYSTYPE *yyvs = yyvsa;    /*  to allow yyoverflow to reallocate them elsewhere */
  18863. X
  18864. X#ifdef YYLSP_NEEDED
  18865. X  YYLTYPE yylsa[YYINITDEPTH];    /*  the location stack            */
  18866. X  YYLTYPE *yyls = yylsa;
  18867. X  YYLTYPE *yylsp;
  18868. X
  18869. X#define YYPOPSTACK   (yyvsp--, yyssp--, yylsp--)
  18870. X#else
  18871. X#define YYPOPSTACK   (yyvsp--, yyssp--)
  18872. X#endif
  18873. X
  18874. X  int yystacksize = YYINITDEPTH;
  18875. X
  18876. X#ifdef YYPURE
  18877. X  int yychar;
  18878. X  YYSTYPE yylval;
  18879. X  int yynerrs;
  18880. X#ifdef YYLSP_NEEDED
  18881. X  YYLTYPE yylloc;
  18882. X#endif
  18883. X#endif
  18884. X
  18885. X  YYSTYPE yyval;        /*  the variable used to return        */
  18886. X                /*  semantic values from the action    */
  18887. X                /*  routines                */
  18888. X
  18889. X  int yylen;
  18890. X
  18891. X#if YYDEBUG != 0
  18892. X  if (yydebug)
  18893. X    fprintf(stderr, "Starting parse\n");
  18894. X#endif
  18895. X
  18896. X  yystate = 0;
  18897. X  yyerrstatus = 0;
  18898. X  yynerrs = 0;
  18899. X  yychar = YYEMPTY;        /* Cause a token to be read.  */
  18900. X
  18901. X  /* Initialize stack pointers.
  18902. X     Waste one element of value and location stack
  18903. X     so that they stay on the same level as the state stack.  */
  18904. X
  18905. X  yyssp = yyss - 1;
  18906. X  yyvsp = yyvs;
  18907. X#ifdef YYLSP_NEEDED
  18908. X  yylsp = yyls;
  18909. X#endif
  18910. X
  18911. X/* Push a new state, which is found in  yystate  .  */
  18912. X/* In all cases, when you get here, the value and location stacks
  18913. X   have just been pushed. so pushing a state here evens the stacks.  */
  18914. Xyynewstate:
  18915. X
  18916. X  *++yyssp = yystate;
  18917. X
  18918. X  if (yyssp >= yyss + yystacksize - 1)
  18919. X    {
  18920. X      /* Give user a chance to reallocate the stack */
  18921. X      /* Use copies of these so that the &'s don't force the real ones into memory. */
  18922. X      YYSTYPE *yyvs1 = yyvs;
  18923. X      short *yyss1 = yyss;
  18924. X#ifdef YYLSP_NEEDED
  18925. X      YYLTYPE *yyls1 = yyls;
  18926. X#endif
  18927. X
  18928. X      /* Get the current used size of the three stacks, in elements.  */
  18929. X      int size = yyssp - yyss + 1;
  18930. X
  18931. X#ifdef yyoverflow
  18932. X      /* Each stack pointer address is followed by the size of
  18933. X     the data in use in that stack, in bytes.  */
  18934. X      yyoverflow("parser stack overflow",
  18935. X         &yyss1, size * sizeof (*yyssp),
  18936. X         &yyvs1, size * sizeof (*yyvsp),
  18937. X#ifdef YYLSP_NEEDED
  18938. X         &yyls1, size * sizeof (*yylsp),
  18939. X#endif
  18940. X         &yystacksize);
  18941. X
  18942. X      yyss = yyss1; yyvs = yyvs1;
  18943. X#ifdef YYLSP_NEEDED
  18944. X      yyls = yyls1;
  18945. X#endif
  18946. X#else /* no yyoverflow */
  18947. X      /* Extend the stack our own way.  */
  18948. X      if (yystacksize >= YYMAXDEPTH)
  18949. X    {
  18950. X      yyerror("parser stack overflow");
  18951. X      return 2;
  18952. X    }
  18953. X      yystacksize *= 2;
  18954. X      if (yystacksize > YYMAXDEPTH)
  18955. X    yystacksize = YYMAXDEPTH;
  18956. X      yyss = (short *) alloca (yystacksize * sizeof (*yyssp));
  18957. X      __yy_bcopy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp));
  18958. X      yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp));
  18959. X      __yy_bcopy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp));
  18960. X#ifdef YYLSP_NEEDED
  18961. X      yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp));
  18962. X      __yy_bcopy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp));
  18963. X#endif
  18964. X#endif /* no yyoverflow */
  18965. X
  18966. X      yyssp = yyss + size - 1;
  18967. X      yyvsp = yyvs + size - 1;
  18968. X#ifdef YYLSP_NEEDED
  18969. X      yylsp = yyls + size - 1;
  18970. X#endif
  18971. X
  18972. X#if YYDEBUG != 0
  18973. X      if (yydebug)
  18974. X    fprintf(stderr, "Stack size increased to %d\n", yystacksize);
  18975. X#endif
  18976. X
  18977. X      if (yyssp >= yyss + yystacksize - 1)
  18978. X    YYABORT;
  18979. X    }
  18980. X
  18981. X#if YYDEBUG != 0
  18982. X  if (yydebug)
  18983. X    fprintf(stderr, "Entering state %d\n", yystate);
  18984. X#endif
  18985. X
  18986. X yybackup:
  18987. X
  18988. X/* Do appropriate processing given the current state.  */
  18989. X/* Read a lookahead token if we need one and don't already have one.  */
  18990. X/* yyresume: */
  18991. X
  18992. X  /* First try to decide what to do without reference to lookahead token.  */
  18993. X
  18994. X  yyn = yypact[yystate];
  18995. X  if (yyn == YYFLAG)
  18996. X    goto yydefault;
  18997. X
  18998. X  /* Not known => get a lookahead token if don't already have one.  */
  18999. X
  19000. X  /* yychar is either YYEMPTY or YYEOF
  19001. X     or a valid token in external form.  */
  19002. X
  19003. X  if (yychar == YYEMPTY)
  19004. X    {
  19005. X#if YYDEBUG != 0
  19006. X      if (yydebug)
  19007. X    fprintf(stderr, "Reading a token: ");
  19008. X#endif
  19009. X      yychar = YYLEX;
  19010. X    }
  19011. X
  19012. X  /* Convert token to internal form (in yychar1) for indexing tables with */
  19013. X
  19014. X  if (yychar <= 0)        /* This means end of input. */
  19015. X    {
  19016. X      yychar1 = 0;
  19017. X      yychar = YYEOF;        /* Don't call YYLEX any more */
  19018. X
  19019. X#if YYDEBUG != 0
  19020. X      if (yydebug)
  19021. X    fprintf(stderr, "Now at end of input.\n");
  19022. X#endif
  19023. X    }
  19024. X  else
  19025. X    {
  19026. X      yychar1 = YYTRANSLATE(yychar);
  19027. X
  19028. X#if YYDEBUG != 0
  19029. X      if (yydebug)
  19030. X    {
  19031. X      fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]);
  19032. X      /* Give the individual parser a way to print the precise meaning
  19033. X         of a token, for further debugging info.  */
  19034. X#ifdef YYPRINT
  19035. X      YYPRINT (stderr, yychar, yylval);
  19036. X#endif
  19037. X      fprintf (stderr, ")\n");
  19038. X    }
  19039. X#endif
  19040. X    }
  19041. X
  19042. X  yyn += yychar1;
  19043. X  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1)
  19044. X    goto yydefault;
  19045. X
  19046. X  yyn = yytable[yyn];
  19047. X
  19048. X  /* yyn is what to do for this token type in this state.
  19049. X     Negative => reduce, -yyn is rule number.
  19050. X     Positive => shift, yyn is new state.
  19051. X       New state is final state => don't bother to shift,
  19052. X       just return success.
  19053. X     0, or most negative number => error.  */
  19054. X
  19055. X  if (yyn < 0)
  19056. X    {
  19057. X      if (yyn == YYFLAG)
  19058. X    goto yyerrlab;
  19059. X      yyn = -yyn;
  19060. X      goto yyreduce;
  19061. X    }
  19062. X  else if (yyn == 0)
  19063. X    goto yyerrlab;
  19064. X
  19065. X  if (yyn == YYFINAL)
  19066. X    YYACCEPT;
  19067. X
  19068. X  /* Shift the lookahead token.  */
  19069. X
  19070. X#if YYDEBUG != 0
  19071. X  if (yydebug)
  19072. X    fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]);
  19073. X#endif
  19074. X
  19075. X  /* Discard the token being shifted unless it is eof.  */
  19076. X  if (yychar != YYEOF)
  19077. X    yychar = YYEMPTY;
  19078. X
  19079. X  *++yyvsp = yylval;
  19080. X#ifdef YYLSP_NEEDED
  19081. X  *++yylsp = yylloc;
  19082. X#endif
  19083. X
  19084. X  /* count tokens shifted since error; after three, turn off error status.  */
  19085. X  if (yyerrstatus) yyerrstatus--;
  19086. X
  19087. X  yystate = yyn;
  19088. X  goto yynewstate;
  19089. X
  19090. X/* Do the default action for the current state.  */
  19091. Xyydefault:
  19092. X
  19093. X  yyn = yydefact[yystate];
  19094. X  if (yyn == 0)
  19095. X    goto yyerrlab;
  19096. X
  19097. X/* Do a reduction.  yyn is the number of a rule to reduce with.  */
  19098. Xyyreduce:
  19099. X  yylen = yyr2[yyn];
  19100. X  yyval = yyvsp[1-yylen]; /* implement default value of the action */
  19101. X
  19102. X#if YYDEBUG != 0
  19103. X  if (yydebug)
  19104. X    {
  19105. X      int i;
  19106. X
  19107. X      fprintf (stderr, "Reducing via rule %d (line %d), ",
  19108. X           yyn, yyrline[yyn]);
  19109. X
  19110. X      /* Print the symboles being reduced, and their result.  */
  19111. X      for (i = yyprhs[yyn]; yyrhs[i] > 0; i++)
  19112. X    fprintf (stderr, "%s ", yytname[yyrhs[i]]);
  19113. X      fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]);
  19114. X    }
  19115. X#endif
  19116. X
  19117. X
  19118. X  switch (yyn) {
  19119. X
  19120. Xcase 3:
  19121. X#line 181 "./getdate.y"
  19122. X{
  19123. X        yyHaveTime++;
  19124. X    ;
  19125. X    break;}
  19126. Xcase 4:
  19127. X#line 184 "./getdate.y"
  19128. X{
  19129. X        yyHaveZone++;
  19130. X    ;
  19131. X    break;}
  19132. Xcase 5:
  19133. X#line 187 "./getdate.y"
  19134. X{
  19135. X        yyHaveDate++;
  19136. X    ;
  19137. X    break;}
  19138. Xcase 6:
  19139. X#line 190 "./getdate.y"
  19140. X{
  19141. X        yyHaveDay++;
  19142. X    ;
  19143. X    break;}
  19144. Xcase 7:
  19145. X#line 193 "./getdate.y"
  19146. X{
  19147. X        yyHaveRel++;
  19148. X    ;
  19149. X    break;}
  19150. Xcase 9:
  19151. X#line 199 "./getdate.y"
  19152. X{
  19153. X        yyHour = yyvsp[-1].Number;
  19154. X        yyMinutes = 0;
  19155. X        yySeconds = 0;
  19156. X        yyMeridian = yyvsp[0].Meridian;
  19157. X    ;
  19158. X    break;}
  19159. Xcase 10:
  19160. X#line 205 "./getdate.y"
  19161. X{
  19162. X        yyHour = yyvsp[-3].Number;
  19163. X        yyMinutes = yyvsp[-1].Number;
  19164. X        yySeconds = 0;
  19165. X        yyMeridian = yyvsp[0].Meridian;
  19166. X    ;
  19167. X    break;}
  19168. Xcase 11:
  19169. X#line 211 "./getdate.y"
  19170. X{
  19171. X        yyHour = yyvsp[-3].Number;
  19172. X        yyMinutes = yyvsp[-1].Number;
  19173. X        yyMeridian = MER24;
  19174. X        yyDSTmode = DSToff;
  19175. X        yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
  19176. X    ;
  19177. X    break;}
  19178. Xcase 12:
  19179. X#line 218 "./getdate.y"
  19180. X{
  19181. X        yyHour = yyvsp[-5].Number;
  19182. X        yyMinutes = yyvsp[-3].Number;
  19183. X        yySeconds = yyvsp[-1].Number;
  19184. X        yyMeridian = yyvsp[0].Meridian;
  19185. X    ;
  19186. X    break;}
  19187. Xcase 13:
  19188. X#line 224 "./getdate.y"
  19189. X{
  19190. X        yyHour = yyvsp[-5].Number;
  19191. X        yyMinutes = yyvsp[-3].Number;
  19192. X        yySeconds = yyvsp[-1].Number;
  19193. X        yyMeridian = MER24;
  19194. X        yyDSTmode = DSToff;
  19195. X        yyTimezone = - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60);
  19196. X    ;
  19197. X    break;}
  19198. Xcase 14:
  19199. X#line 234 "./getdate.y"
  19200. X{
  19201. X        yyTimezone = yyvsp[0].Number;
  19202. X        yyDSTmode = DSToff;
  19203. X    ;
  19204. X    break;}
  19205. Xcase 15:
  19206. X#line 238 "./getdate.y"
  19207. X{
  19208. X        yyTimezone = yyvsp[0].Number;
  19209. X        yyDSTmode = DSTon;
  19210. X    ;
  19211. X    break;}
  19212. Xcase 16:
  19213. X#line 243 "./getdate.y"
  19214. X{
  19215. X        yyTimezone = yyvsp[-1].Number;
  19216. X        yyDSTmode = DSTon;
  19217. X    ;
  19218. X    break;}
  19219. Xcase 17:
  19220. X#line 249 "./getdate.y"
  19221. X{
  19222. X        yyDayOrdinal = 1;
  19223. X        yyDayNumber = yyvsp[0].Number;
  19224. X    ;
  19225. X    break;}
  19226. Xcase 18:
  19227. X#line 253 "./getdate.y"
  19228. X{
  19229. X        yyDayOrdinal = 1;
  19230. X        yyDayNumber = yyvsp[-1].Number;
  19231. X    ;
  19232. X    break;}
  19233. Xcase 19:
  19234. X#line 257 "./getdate.y"
  19235. X{
  19236. X        yyDayOrdinal = yyvsp[-1].Number;
  19237. X        yyDayNumber = yyvsp[0].Number;
  19238. X    ;
  19239. X    break;}
  19240. Xcase 20:
  19241. X#line 263 "./getdate.y"
  19242. X{
  19243. X        yyMonth = yyvsp[-2].Number;
  19244. X        yyDay = yyvsp[0].Number;
  19245. X    ;
  19246. X    break;}
  19247. Xcase 21:
  19248. X#line 267 "./getdate.y"
  19249. X{
  19250. X        yyMonth = yyvsp[-4].Number;
  19251. X        yyDay = yyvsp[-2].Number;
  19252. X        yyYear = yyvsp[0].Number;
  19253. X    ;
  19254. X    break;}
  19255. Xcase 22:
  19256. X#line 272 "./getdate.y"
  19257. X{
  19258. X        /* ISO 8601 format.  yyyy-mm-dd.  */
  19259. X        yyYear = yyvsp[-2].Number;
  19260. X        yyMonth = -yyvsp[-1].Number;
  19261. X        yyDay = -yyvsp[0].Number;
  19262. X    ;
  19263. X    break;}
  19264. Xcase 23:
  19265. X#line 278 "./getdate.y"
  19266. X{
  19267. X        yyMonth = yyvsp[-1].Number;
  19268. X        yyDay = yyvsp[0].Number;
  19269. X    ;
  19270. X    break;}
  19271. Xcase 24:
  19272. X#line 282 "./getdate.y"
  19273. X{
  19274. X        yyMonth = yyvsp[-3].Number;
  19275. X        yyDay = yyvsp[-2].Number;
  19276. X        yyYear = yyvsp[0].Number;
  19277. X    ;
  19278. X    break;}
  19279. Xcase 25:
  19280. X#line 287 "./getdate.y"
  19281. X{
  19282. X        yyMonth = yyvsp[0].Number;
  19283. X        yyDay = yyvsp[-1].Number;
  19284. X    ;
  19285. X    break;}
  19286. Xcase 26:
  19287. X#line 291 "./getdate.y"
  19288. X{
  19289. X        yyMonth = yyvsp[-1].Number;
  19290. X        yyDay = yyvsp[-2].Number;
  19291. X        yyYear = yyvsp[0].Number;
  19292. X    ;
  19293. X    break;}
  19294. Xcase 27:
  19295. X#line 298 "./getdate.y"
  19296. X{
  19297. X        yyRelSeconds = -yyRelSeconds;
  19298. X        yyRelMonth = -yyRelMonth;
  19299. X    ;
  19300. X    break;}
  19301. Xcase 29:
  19302. X#line 305 "./getdate.y"
  19303. X{
  19304. X        yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
  19305. X    ;
  19306. X    break;}
  19307. Xcase 30:
  19308. X#line 308 "./getdate.y"
  19309. X{
  19310. X        yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number * 60L;
  19311. X    ;
  19312. X    break;}
  19313. Xcase 31:
  19314. X#line 311 "./getdate.y"
  19315. X{
  19316. X        yyRelSeconds += yyvsp[0].Number * 60L;
  19317. X    ;
  19318. X    break;}
  19319. Xcase 32:
  19320. X#line 314 "./getdate.y"
  19321. X{
  19322. X        yyRelSeconds += yyvsp[-1].Number;
  19323. X    ;
  19324. X    break;}
  19325. Xcase 33:
  19326. X#line 317 "./getdate.y"
  19327. X{
  19328. X        yyRelSeconds += yyvsp[-1].Number;
  19329. X    ;
  19330. X    break;}
  19331. Xcase 34:
  19332. X#line 320 "./getdate.y"
  19333. X{
  19334. X        yyRelSeconds++;
  19335. X    ;
  19336. X    break;}
  19337. Xcase 35:
  19338. X#line 323 "./getdate.y"
  19339. X{
  19340. X        yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
  19341. X    ;
  19342. X    break;}
  19343. Xcase 36:
  19344. X#line 326 "./getdate.y"
  19345. X{
  19346. X        yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
  19347. X    ;
  19348. X    break;}
  19349. Xcase 37:
  19350. X#line 329 "./getdate.y"
  19351. X{
  19352. X        yyRelMonth += yyvsp[0].Number;
  19353. X    ;
  19354. X    break;}
  19355. Xcase 38:
  19356. X#line 334 "./getdate.y"
  19357. X{
  19358. X        if (yyHaveTime && yyHaveDate && !yyHaveRel)
  19359. X        yyYear = yyvsp[0].Number;
  19360. X        else {
  19361. X        if(yyvsp[0].Number>10000) {
  19362. X            time_t date_part;
  19363. X
  19364. X            date_part= yyvsp[0].Number/10000;
  19365. X            yyHaveDate++;
  19366. X            yyDay= (date_part)%100;
  19367. X            yyMonth= (date_part/100)%100;
  19368. X            yyYear = date_part/10000;
  19369. X        } 
  19370. X            yyHaveTime++;
  19371. X        if (yyvsp[0].Number < 100) {
  19372. X            yyHour = yyvsp[0].Number;
  19373. X            yyMinutes = 0;
  19374. X        }
  19375. X        else {
  19376. X            yyHour = yyvsp[0].Number / 100;
  19377. X            yyMinutes = yyvsp[0].Number % 100;
  19378. X        }
  19379. X        yySeconds = 0;
  19380. X        yyMeridian = MER24;
  19381. X        }
  19382. X    ;
  19383. X    break;}
  19384. Xcase 39:
  19385. X#line 362 "./getdate.y"
  19386. X{
  19387. X        yyval.Meridian = MER24;
  19388. X    ;
  19389. X    break;}
  19390. Xcase 40:
  19391. X#line 365 "./getdate.y"
  19392. X{
  19393. X        yyval.Meridian = yyvsp[0].Meridian;
  19394. X    ;
  19395. X    break;}
  19396. X}
  19397. X   /* the action file gets copied in in place of this dollarsign */
  19398. X#line 440 "bison.simple"
  19399. X
  19400. X  yyvsp -= yylen;
  19401. X  yyssp -= yylen;
  19402. X#ifdef YYLSP_NEEDED
  19403. X  yylsp -= yylen;
  19404. X#endif
  19405. X
  19406. X#if YYDEBUG != 0
  19407. X  if (yydebug)
  19408. X    {
  19409. X      short *ssp1 = yyss - 1;
  19410. X      fprintf (stderr, "state stack now");
  19411. X      while (ssp1 != yyssp)
  19412. X    fprintf (stderr, " %d", *++ssp1);
  19413. X      fprintf (stderr, "\n");
  19414. X    }
  19415. X#endif
  19416. X
  19417. X  *++yyvsp = yyval;
  19418. X
  19419. X#ifdef YYLSP_NEEDED
  19420. X  yylsp++;
  19421. X  if (yylen == 0)
  19422. X    {
  19423. X      yylsp->first_line = yylloc.first_line;
  19424. X      yylsp->first_column = yylloc.first_column;
  19425. X      yylsp->last_line = (yylsp-1)->last_line;
  19426. X      yylsp->last_column = (yylsp-1)->last_column;
  19427. X      yylsp->text = 0;
  19428. X    }
  19429. X  else
  19430. X    {
  19431. X      yylsp->last_line = (yylsp+yylen-1)->last_line;
  19432. X      yylsp->last_column = (yylsp+yylen-1)->last_column;
  19433. X    }
  19434. X#endif
  19435. X
  19436. X  /* Now "shift" the result of the reduction.
  19437. X     Determine what state that goes to,
  19438. X     based on the state we popped back to
  19439. X     and the rule number reduced by.  */
  19440. X
  19441. X  yyn = yyr1[yyn];
  19442. X
  19443. X  yystate = yypgoto[yyn - YYNTBASE] + *yyssp;
  19444. X  if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp)
  19445. X    yystate = yytable[yystate];
  19446. X  else
  19447. X    yystate = yydefgoto[yyn - YYNTBASE];
  19448. X
  19449. X  goto yynewstate;
  19450. X
  19451. Xyyerrlab:   /* here on detecting error */
  19452. X
  19453. X  if (! yyerrstatus)
  19454. X    /* If not already recovering from an error, report this error.  */
  19455. X    {
  19456. X      ++yynerrs;
  19457. X
  19458. X#ifdef YYERROR_VERBOSE
  19459. X      yyn = yypact[yystate];
  19460. X
  19461. X      if (yyn > YYFLAG && yyn < YYLAST)
  19462. X    {
  19463. X      int size = 0;
  19464. X      char *msg;
  19465. X      int x, count;
  19466. X
  19467. X      count = 0;
  19468. X      for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++)
  19469. X        if (yycheck[x + yyn] == x)
  19470. X          size += strlen(yytname[x]) + 15, count++;
  19471. X      msg = (char *) malloc(size + 15);
  19472. X      if (msg != 0)
  19473. X        {
  19474. X          strcpy(msg, "parse error");
  19475. X
  19476. X          if (count < 5)
  19477. X        {
  19478. X          count = 0;
  19479. X          for (x = 0; x < (sizeof(yytname) / sizeof(char *)); x++)
  19480. X            if (yycheck[x + yyn] == x)
  19481. X              {
  19482. X            strcat(msg, count == 0 ? ", expecting `" : " or `");
  19483. X            strcat(msg, yytname[x]);
  19484. X            strcat(msg, "'");
  19485. X            count++;
  19486. X              }
  19487. X        }
  19488. X          yyerror(msg);
  19489. X          free(msg);
  19490. X        }
  19491. X      else
  19492. X        yyerror ("parse error; also virtual memory exceeded");
  19493. X    }
  19494. X      else
  19495. X#endif /* YYERROR_VERBOSE */
  19496. X    yyerror("parse error");
  19497. X    }
  19498. X
  19499. Xyyerrlab1:   /* here on error raised explicitly by an action */
  19500. X
  19501. X  if (yyerrstatus == 3)
  19502. X    {
  19503. X      /* if just tried and failed to reuse lookahead token after an error, discard it.  */
  19504. X
  19505. X      /* return failure if at end of input */
  19506. X      if (yychar == YYEOF)
  19507. X    YYABORT;
  19508. X
  19509. X#if YYDEBUG != 0
  19510. X      if (yydebug)
  19511. X    fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]);
  19512. X#endif
  19513. X
  19514. X      yychar = YYEMPTY;
  19515. X    }
  19516. X
  19517. X  /* Else will try to reuse lookahead token
  19518. X     after shifting the error token.  */
  19519. X
  19520. X  yyerrstatus = 3;        /* Each real token shifted decrements this */
  19521. X
  19522. X  goto yyerrhandle;
  19523. X
  19524. Xyyerrdefault:  /* current state does not do anything special for the error token. */
  19525. X
  19526. X#if 0
  19527. X  /* This is wrong; only states that explicitly want error tokens
  19528. X     should shift them.  */
  19529. X  yyn = yydefact[yystate];  /* If its default is to accept any token, ok.  Otherwise pop it.*/
  19530. X  if (yyn) goto yydefault;
  19531. X#endif
  19532. X
  19533. Xyyerrpop:   /* pop the current state because it cannot handle the error token */
  19534. X
  19535. X  if (yyssp == yyss) YYABORT;
  19536. X  yyvsp--;
  19537. X  yystate = *--yyssp;
  19538. X#ifdef YYLSP_NEEDED
  19539. X  yylsp--;
  19540. X#endif
  19541. X
  19542. X#if YYDEBUG != 0
  19543. X  if (yydebug)
  19544. X    {
  19545. X      short *ssp1 = yyss - 1;
  19546. X      fprintf (stderr, "Error: state stack now");
  19547. X      while (ssp1 != yyssp)
  19548. X    fprintf (stderr, " %d", *++ssp1);
  19549. X      fprintf (stderr, "\n");
  19550. X    }
  19551. X#endif
  19552. X
  19553. Xyyerrhandle:
  19554. X
  19555. X  yyn = yypact[yystate];
  19556. X  if (yyn == YYFLAG)
  19557. X    goto yyerrdefault;
  19558. X
  19559. X  yyn += YYTERROR;
  19560. X  if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR)
  19561. X    goto yyerrdefault;
  19562. X
  19563. X  yyn = yytable[yyn];
  19564. X  if (yyn < 0)
  19565. X    {
  19566. X      if (yyn == YYFLAG)
  19567. X    goto yyerrpop;
  19568. X      yyn = -yyn;
  19569. X      goto yyreduce;
  19570. X    }
  19571. X  else if (yyn == 0)
  19572. X    goto yyerrpop;
  19573. X
  19574. X  if (yyn == YYFINAL)
  19575. X    YYACCEPT;
  19576. X
  19577. X#if YYDEBUG != 0
  19578. X  if (yydebug)
  19579. X    fprintf(stderr, "Shifting error token, ");
  19580. X#endif
  19581. X
  19582. X  *++yyvsp = yylval;
  19583. X#ifdef YYLSP_NEEDED
  19584. X  *++yylsp = yylloc;
  19585. X#endif
  19586. X
  19587. X  yystate = yyn;
  19588. X  goto yynewstate;
  19589. X}
  19590. X#line 370 "./getdate.y"
  19591. X
  19592. X
  19593. X/* Month and day table. */
  19594. Xstatic TABLE const MonthDayTable[] = {
  19595. X    { "january",    tMONTH,  1 },
  19596. X    { "february",    tMONTH,  2 },
  19597. X    { "march",        tMONTH,  3 },
  19598. X    { "april",        tMONTH,  4 },
  19599. X    { "may",        tMONTH,  5 },
  19600. X    { "june",        tMONTH,  6 },
  19601. X    { "july",        tMONTH,  7 },
  19602. X    { "august",        tMONTH,  8 },
  19603. X    { "september",    tMONTH,  9 },
  19604. X    { "sept",        tMONTH,  9 },
  19605. X    { "october",    tMONTH, 10 },
  19606. X    { "november",    tMONTH, 11 },
  19607. X    { "december",    tMONTH, 12 },
  19608. X    { "sunday",        tDAY, 0 },
  19609. X    { "monday",        tDAY, 1 },
  19610. X    { "tuesday",    tDAY, 2 },
  19611. X    { "tues",        tDAY, 2 },
  19612. X    { "wednesday",    tDAY, 3 },
  19613. X    { "wednes",        tDAY, 3 },
  19614. X    { "thursday",    tDAY, 4 },
  19615. X    { "thur",        tDAY, 4 },
  19616. X    { "thurs",        tDAY, 4 },
  19617. X    { "friday",        tDAY, 5 },
  19618. X    { "saturday",    tDAY, 6 },
  19619. X    { NULL }
  19620. X};
  19621. X
  19622. X/* Time units table. */
  19623. Xstatic TABLE const UnitsTable[] = {
  19624. X    { "year",        tMONTH_UNIT,    12 },
  19625. X    { "month",        tMONTH_UNIT,    1 },
  19626. X    { "fortnight",    tMINUTE_UNIT,    14 * 24 * 60 },
  19627. X    { "week",        tMINUTE_UNIT,    7 * 24 * 60 },
  19628. X    { "day",        tMINUTE_UNIT,    1 * 24 * 60 },
  19629. X    { "hour",        tMINUTE_UNIT,    60 },
  19630. X    { "minute",        tMINUTE_UNIT,    1 },
  19631. X    { "min",        tMINUTE_UNIT,    1 },
  19632. X    { "second",        tSEC_UNIT,    1 },
  19633. X    { "sec",        tSEC_UNIT,    1 },
  19634. X    { NULL }
  19635. X};
  19636. X
  19637. X/* Assorted relative-time words. */
  19638. Xstatic TABLE const OtherTable[] = {
  19639. X    { "tomorrow",    tMINUTE_UNIT,    1 * 24 * 60 },
  19640. X    { "yesterday",    tMINUTE_UNIT,    -1 * 24 * 60 },
  19641. X    { "today",        tMINUTE_UNIT,    0 },
  19642. X    { "now",        tMINUTE_UNIT,    0 },
  19643. X    { "last",        tUNUMBER,    -1 },
  19644. X    { "this",        tMINUTE_UNIT,    0 },
  19645. X    { "next",        tUNUMBER,    2 },
  19646. X    { "first",        tUNUMBER,    1 },
  19647. X/*  { "second",        tUNUMBER,    2 }, */
  19648. X    { "third",        tUNUMBER,    3 },
  19649. X    { "fourth",        tUNUMBER,    4 },
  19650. X    { "fifth",        tUNUMBER,    5 },
  19651. X    { "sixth",        tUNUMBER,    6 },
  19652. X    { "seventh",    tUNUMBER,    7 },
  19653. X    { "eighth",        tUNUMBER,    8 },
  19654. X    { "ninth",        tUNUMBER,    9 },
  19655. X    { "tenth",        tUNUMBER,    10 },
  19656. X    { "eleventh",    tUNUMBER,    11 },
  19657. X    { "twelfth",    tUNUMBER,    12 },
  19658. X    { "ago",        tAGO,    1 },
  19659. X    { NULL }
  19660. X};
  19661. X
  19662. X/* The timezone table. */
  19663. X/* Some of these are commented out because a time_t can't store a float. */
  19664. Xstatic TABLE const TimezoneTable[] = {
  19665. X    { "gmt",    tZONE,     HOUR( 0) },    /* Greenwich Mean */
  19666. X    { "ut",    tZONE,     HOUR( 0) },    /* Universal (Coordinated) */
  19667. X    { "utc",    tZONE,     HOUR( 0) },
  19668. X    { "wet",    tZONE,     HOUR( 0) },    /* Western European */
  19669. X    { "bst",    tDAYZONE,  HOUR( 0) },    /* British Summer */
  19670. X    { "wat",    tZONE,     HOUR( 1) },    /* West Africa */
  19671. X    { "at",    tZONE,     HOUR( 2) },    /* Azores */
  19672. X#if    0
  19673. X    /* For completeness.  BST is also British Summer, and GST is
  19674. X     * also Guam Standard. */
  19675. X    { "bst",    tZONE,     HOUR( 3) },    /* Brazil Standard */
  19676. X    { "gst",    tZONE,     HOUR( 3) },    /* Greenland Standard */
  19677. X#endif
  19678. X#if 0
  19679. X    { "nft",    tZONE,     HOUR(3.5) },    /* Newfoundland */
  19680. X    { "nst",    tZONE,     HOUR(3.5) },    /* Newfoundland Standard */
  19681. X    { "ndt",    tDAYZONE,  HOUR(3.5) },    /* Newfoundland Daylight */
  19682. X#endif
  19683. X    { "ast",    tZONE,     HOUR( 4) },    /* Atlantic Standard */
  19684. X    { "adt",    tDAYZONE,  HOUR( 4) },    /* Atlantic Daylight */
  19685. X    { "est",    tZONE,     HOUR( 5) },    /* Eastern Standard */
  19686. X    { "edt",    tDAYZONE,  HOUR( 5) },    /* Eastern Daylight */
  19687. X    { "cst",    tZONE,     HOUR( 6) },    /* Central Standard */
  19688. X    { "cdt",    tDAYZONE,  HOUR( 6) },    /* Central Daylight */
  19689. X    { "mst",    tZONE,     HOUR( 7) },    /* Mountain Standard */
  19690. X    { "mdt",    tDAYZONE,  HOUR( 7) },    /* Mountain Daylight */
  19691. X    { "pst",    tZONE,     HOUR( 8) },    /* Pacific Standard */
  19692. X    { "pdt",    tDAYZONE,  HOUR( 8) },    /* Pacific Daylight */
  19693. X    { "yst",    tZONE,     HOUR( 9) },    /* Yukon Standard */
  19694. X    { "ydt",    tDAYZONE,  HOUR( 9) },    /* Yukon Daylight */
  19695. X    { "hst",    tZONE,     HOUR(10) },    /* Hawaii Standard */
  19696. X    { "hdt",    tDAYZONE,  HOUR(10) },    /* Hawaii Daylight */
  19697. X    { "cat",    tZONE,     HOUR(10) },    /* Central Alaska */
  19698. X    { "ahst",    tZONE,     HOUR(10) },    /* Alaska-Hawaii Standard */
  19699. X    { "nt",    tZONE,     HOUR(11) },    /* Nome */
  19700. X    { "idlw",    tZONE,     HOUR(12) },    /* International Date Line West */
  19701. X    { "cet",    tZONE,     -HOUR(1) },    /* Central European */
  19702. X    { "met",    tZONE,     -HOUR(1) },    /* Middle European */
  19703. X    { "mewt",    tZONE,     -HOUR(1) },    /* Middle European Winter */
  19704. X    { "mest",    tDAYZONE,  -HOUR(1) },    /* Middle European Summer */
  19705. X    { "swt",    tZONE,     -HOUR(1) },    /* Swedish Winter */
  19706. X    { "sst",    tDAYZONE,  -HOUR(1) },    /* Swedish Summer */
  19707. X    { "fwt",    tZONE,     -HOUR(1) },    /* French Winter */
  19708. X    { "fst",    tDAYZONE,  -HOUR(1) },    /* French Summer */
  19709. X    { "eet",    tZONE,     -HOUR(2) },    /* Eastern Europe, USSR Zone 1 */
  19710. X    { "bt",    tZONE,     -HOUR(3) },    /* Baghdad, USSR Zone 2 */
  19711. X#if 0
  19712. X    { "it",    tZONE,     -HOUR(3.5) },/* Iran */
  19713. X#endif
  19714. X    { "zp4",    tZONE,     -HOUR(4) },    /* USSR Zone 3 */
  19715. X    { "zp5",    tZONE,     -HOUR(5) },    /* USSR Zone 4 */
  19716. X#if 0
  19717. X    { "ist",    tZONE,     -HOUR(5.5) },/* Indian Standard */
  19718. X#endif
  19719. X    { "zp6",    tZONE,     -HOUR(6) },    /* USSR Zone 5 */
  19720. X#if    0
  19721. X    /* For completeness.  NST is also Newfoundland Stanard, and SST is
  19722. X     * also Swedish Summer. */
  19723. X    { "nst",    tZONE,     -HOUR(6.5) },/* North Sumatra */
  19724. X    { "sst",    tZONE,     -HOUR(7) },    /* South Sumatra, USSR Zone 6 */
  19725. X#endif    /* 0 */
  19726. X    { "wast",    tZONE,     -HOUR(7) },    /* West Australian Standard */
  19727. X    { "wadt",    tDAYZONE,  -HOUR(7) },    /* West Australian Daylight */
  19728. X#if 0
  19729. X    { "jt",    tZONE,     -HOUR(7.5) },/* Java (3pm in Cronusland!) */
  19730. X#endif
  19731. X    { "cct",    tZONE,     -HOUR(8) },    /* China Coast, USSR Zone 7 */
  19732. X    { "jst",    tZONE,     -HOUR(9) },    /* Japan Standard, USSR Zone 8 */
  19733. X#if 0
  19734. X    { "cast",    tZONE,     -HOUR(9.5) },/* Central Australian Standard */
  19735. X    { "cadt",    tDAYZONE,  -HOUR(9.5) },/* Central Australian Daylight */
  19736. X#endif
  19737. X    { "east",    tZONE,     -HOUR(10) },    /* Eastern Australian Standard */
  19738. X    { "eadt",    tDAYZONE,  -HOUR(10) },    /* Eastern Australian Daylight */
  19739. X    { "gst",    tZONE,     -HOUR(10) },    /* Guam Standard, USSR Zone 9 */
  19740. X    { "nzt",    tZONE,     -HOUR(12) },    /* New Zealand */
  19741. X    { "nzst",    tZONE,     -HOUR(12) },    /* New Zealand Standard */
  19742. X    { "nzdt",    tDAYZONE,  -HOUR(12) },    /* New Zealand Daylight */
  19743. X    { "idle",    tZONE,     -HOUR(12) },    /* International Date Line East */
  19744. X    {  NULL  }
  19745. X};
  19746. X
  19747. X/* Military timezone table. */
  19748. Xstatic TABLE const MilitaryTable[] = {
  19749. X    { "a",    tZONE,    HOUR(  1) },
  19750. X    { "b",    tZONE,    HOUR(  2) },
  19751. X    { "c",    tZONE,    HOUR(  3) },
  19752. X    { "d",    tZONE,    HOUR(  4) },
  19753. X    { "e",    tZONE,    HOUR(  5) },
  19754. X    { "f",    tZONE,    HOUR(  6) },
  19755. X    { "g",    tZONE,    HOUR(  7) },
  19756. X    { "h",    tZONE,    HOUR(  8) },
  19757. X    { "i",    tZONE,    HOUR(  9) },
  19758. X    { "k",    tZONE,    HOUR( 10) },
  19759. X    { "l",    tZONE,    HOUR( 11) },
  19760. X    { "m",    tZONE,    HOUR( 12) },
  19761. X    { "n",    tZONE,    HOUR(- 1) },
  19762. X    { "o",    tZONE,    HOUR(- 2) },
  19763. X    { "p",    tZONE,    HOUR(- 3) },
  19764. X    { "q",    tZONE,    HOUR(- 4) },
  19765. X    { "r",    tZONE,    HOUR(- 5) },
  19766. X    { "s",    tZONE,    HOUR(- 6) },
  19767. X    { "t",    tZONE,    HOUR(- 7) },
  19768. X    { "u",    tZONE,    HOUR(- 8) },
  19769. X    { "v",    tZONE,    HOUR(- 9) },
  19770. X    { "w",    tZONE,    HOUR(-10) },
  19771. X    { "x",    tZONE,    HOUR(-11) },
  19772. X    { "y",    tZONE,    HOUR(-12) },
  19773. X    { "z",    tZONE,    HOUR(  0) },
  19774. X    { NULL }
  19775. X};
  19776. X
  19777. X
  19778. X
  19779. X
  19780. X/* ARGSUSED */
  19781. Xstatic int
  19782. Xyyerror(s)
  19783. X    char    *s;
  19784. X{
  19785. X  return 0;
  19786. X}
  19787. X
  19788. X
  19789. Xstatic time_t
  19790. XToSeconds(Hours, Minutes, Seconds, Meridian)
  19791. X    time_t    Hours;
  19792. X    time_t    Minutes;
  19793. X    time_t    Seconds;
  19794. X    MERIDIAN    Meridian;
  19795. X{
  19796. X    if (Minutes < 0 || Minutes > 59 || Seconds < 0 || Seconds > 59)
  19797. X    return -1;
  19798. X    switch (Meridian) {
  19799. X    case MER24:
  19800. X    if (Hours < 0 || Hours > 23)
  19801. X        return -1;
  19802. X    return (Hours * 60L + Minutes) * 60L + Seconds;
  19803. X    case MERam:
  19804. X    if (Hours < 1 || Hours > 12)
  19805. X        return -1;
  19806. X    return (Hours * 60L + Minutes) * 60L + Seconds;
  19807. X    case MERpm:
  19808. X    if (Hours < 1 || Hours > 12)
  19809. X        return -1;
  19810. X    return ((Hours + 12) * 60L + Minutes) * 60L + Seconds;
  19811. X    }
  19812. X    /* NOTREACHED */
  19813. X}
  19814. X
  19815. X
  19816. Xstatic time_t
  19817. XConvert(Month, Day, Year, Hours, Minutes, Seconds, Meridian, DSTmode)
  19818. X    time_t    Month;
  19819. X    time_t    Day;
  19820. X    time_t    Year;
  19821. X    time_t    Hours;
  19822. X    time_t    Minutes;
  19823. X    time_t    Seconds;
  19824. X    MERIDIAN    Meridian;
  19825. X    DSTMODE    DSTmode;
  19826. X{
  19827. X    static int DaysInMonth[12] = {
  19828. X    31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  19829. X    };
  19830. X    time_t    tod;
  19831. X    time_t    Julian;
  19832. X    int        i;
  19833. X
  19834. X    if (Year < 0)
  19835. X    Year = -Year;
  19836. X    if (Year < 100)
  19837. X    Year += 1900;
  19838. X    DaysInMonth[1] = Year % 4 == 0 && (Year % 100 != 0 || Year % 400 == 0)
  19839. X            ? 29 : 28;
  19840. X    if (Year < EPOCH || Year > 1999
  19841. X     || Month < 1 || Month > 12
  19842. X     /* Lint fluff:  "conversion from long may lose accuracy" */
  19843. X     || Day < 1 || Day > DaysInMonth[(int)--Month])
  19844. X    return -1;
  19845. X
  19846. X    for (Julian = Day - 1, i = 0; i < Month; i++)
  19847. X    Julian += DaysInMonth[i];
  19848. X    for (i = EPOCH; i < Year; i++)
  19849. X    Julian += 365 + (i % 4 == 0);
  19850. X    Julian *= SECSPERDAY;
  19851. X    Julian += yyTimezone * 60L;
  19852. X    if ((tod = ToSeconds(Hours, Minutes, Seconds, Meridian)) < 0)
  19853. X    return -1;
  19854. X    Julian += tod;
  19855. X    if (DSTmode == DSTon
  19856. X     || (DSTmode == DSTmaybe && localtime(&Julian)->tm_isdst))
  19857. X    Julian -= 60 * 60;
  19858. X    return Julian;
  19859. X}
  19860. X
  19861. X
  19862. Xstatic time_t
  19863. XDSTcorrect(Start, Future)
  19864. X    time_t    Start;
  19865. X    time_t    Future;
  19866. X{
  19867. X    time_t    StartDay;
  19868. X    time_t    FutureDay;
  19869. X
  19870. X    StartDay = (localtime(&Start)->tm_hour + 1) % 24;
  19871. X    FutureDay = (localtime(&Future)->tm_hour + 1) % 24;
  19872. X    return (Future - Start) + (StartDay - FutureDay) * 60L * 60L;
  19873. X}
  19874. X
  19875. X
  19876. Xstatic time_t
  19877. XRelativeDate(Start, DayOrdinal, DayNumber)
  19878. X    time_t    Start;
  19879. X    time_t    DayOrdinal;
  19880. X    time_t    DayNumber;
  19881. X{
  19882. X    struct tm    *tm;
  19883. X    time_t    now;
  19884. X
  19885. X    now = Start;
  19886. X    tm = localtime(&now);
  19887. X    now += SECSPERDAY * ((DayNumber - tm->tm_wday + 7) % 7);
  19888. X    now += 7 * SECSPERDAY * (DayOrdinal <= 0 ? DayOrdinal : DayOrdinal - 1);
  19889. X    return DSTcorrect(Start, now);
  19890. X}
  19891. X
  19892. X
  19893. Xstatic time_t
  19894. XRelativeMonth(Start, RelMonth)
  19895. X    time_t    Start;
  19896. X    time_t    RelMonth;
  19897. X{
  19898. X    struct tm    *tm;
  19899. X    time_t    Month;
  19900. X    time_t    Year;
  19901. X
  19902. X    if (RelMonth == 0)
  19903. X    return 0;
  19904. X    tm = localtime(&Start);
  19905. X    Month = 12 * tm->tm_year + tm->tm_mon + RelMonth;
  19906. X    Year = Month / 12;
  19907. X    Month = Month % 12 + 1;
  19908. X    return DSTcorrect(Start,
  19909. X        Convert(Month, (time_t)tm->tm_mday, Year,
  19910. X        (time_t)tm->tm_hour, (time_t)tm->tm_min, (time_t)tm->tm_sec,
  19911. X        MER24, DSTmaybe));
  19912. X}
  19913. X
  19914. X
  19915. Xstatic int
  19916. XLookupWord(buff)
  19917. X    char        *buff;
  19918. X{
  19919. X    register char    *p;
  19920. X    register char    *q;
  19921. X    register const TABLE    *tp;
  19922. X    int            i;
  19923. X    int            abbrev;
  19924. X
  19925. X    /* Make it lowercase. */
  19926. X    for (p = buff; *p; p++)
  19927. X    if (isupper(*p))
  19928. X        *p = tolower(*p);
  19929. X
  19930. X    if (strcmp(buff, "am") == 0 || strcmp(buff, "a.m.") == 0) {
  19931. X    yylval.Meridian = MERam;
  19932. X    return tMERIDIAN;
  19933. X    }
  19934. X    if (strcmp(buff, "pm") == 0 || strcmp(buff, "p.m.") == 0) {
  19935. X    yylval.Meridian = MERpm;
  19936. X    return tMERIDIAN;
  19937. X    }
  19938. X
  19939. X    /* See if we have an abbreviation for a month. */
  19940. X    if (strlen(buff) == 3)
  19941. X    abbrev = 1;
  19942. X    else if (strlen(buff) == 4 && buff[3] == '.') {
  19943. X    abbrev = 1;
  19944. X    buff[3] = '\0';
  19945. X    }
  19946. X    else
  19947. X    abbrev = 0;
  19948. X
  19949. X    for (tp = MonthDayTable; tp->name; tp++) {
  19950. X    if (abbrev) {
  19951. X        if (strncmp(buff, tp->name, 3) == 0) {
  19952. X        yylval.Number = tp->value;
  19953. X        return tp->type;
  19954. X        }
  19955. X    }
  19956. X    else if (strcmp(buff, tp->name) == 0) {
  19957. X        yylval.Number = tp->value;
  19958. X        return tp->type;
  19959. X    }
  19960. X    }
  19961. X
  19962. X    for (tp = TimezoneTable; tp->name; tp++)
  19963. X    if (strcmp(buff, tp->name) == 0) {
  19964. X        yylval.Number = tp->value;
  19965. X        return tp->type;
  19966. X    }
  19967. X
  19968. X    if (strcmp(buff, "dst") == 0) 
  19969. X    return tDST;
  19970. X
  19971. X    for (tp = UnitsTable; tp->name; tp++)
  19972. X    if (strcmp(buff, tp->name) == 0) {
  19973. X        yylval.Number = tp->value;
  19974. X        return tp->type;
  19975. X    }
  19976. X
  19977. X    /* Strip off any plural and try the units table again. */
  19978. X    i = strlen(buff) - 1;
  19979. X    if (buff[i] == 's') {
  19980. X    buff[i] = '\0';
  19981. X    for (tp = UnitsTable; tp->name; tp++)
  19982. X        if (strcmp(buff, tp->name) == 0) {
  19983. X        yylval.Number = tp->value;
  19984. X        return tp->type;
  19985. X        }
  19986. X    buff[i] = 's';        /* Put back for "this" in OtherTable. */
  19987. X    }
  19988. X
  19989. X    for (tp = OtherTable; tp->name; tp++)
  19990. X    if (strcmp(buff, tp->name) == 0) {
  19991. X        yylval.Number = tp->value;
  19992. X        return tp->type;
  19993. X    }
  19994. X
  19995. X    /* Military timezones. */
  19996. X    if (buff[1] == '\0' && isalpha(*buff)) {
  19997. X    for (tp = MilitaryTable; tp->name; tp++)
  19998. X        if (strcmp(buff, tp->name) == 0) {
  19999. X        yylval.Number = tp->value;
  20000. X        return tp->type;
  20001. X        }
  20002. X    }
  20003. X
  20004. X    /* Drop out any periods and try the timezone table again. */
  20005. X    for (i = 0, p = q = buff; *q; q++)
  20006. X    if (*q != '.')
  20007. X        *p++ = *q;
  20008. X    else
  20009. X        i++;
  20010. X    *p = '\0';
  20011. X    if (i)
  20012. X    for (tp = TimezoneTable; tp->name; tp++)
  20013. X        if (strcmp(buff, tp->name) == 0) {
  20014. X        yylval.Number = tp->value;
  20015. X        return tp->type;
  20016. X        }
  20017. X
  20018. X    return tID;
  20019. X}
  20020. X
  20021. X
  20022. Xstatic int
  20023. Xyylex()
  20024. X{
  20025. X    register char    c;
  20026. X    register char    *p;
  20027. X    char        buff[20];
  20028. X    int            Count;
  20029. X    int            sign;
  20030. X
  20031. X    for ( ; ; ) {
  20032. X    while (isspace(*yyInput))
  20033. X        yyInput++;
  20034. X
  20035. X    if (isdigit(c = *yyInput) || c == '-' || c == '+') {
  20036. X        if (c == '-' || c == '+') {
  20037. X        sign = c == '-' ? -1 : 1;
  20038. X        if (!isdigit(*++yyInput))
  20039. X            /* skip the '-' sign */
  20040. X            continue;
  20041. X        }
  20042. X        else
  20043. X        sign = 0;
  20044. X        for (yylval.Number = 0; isdigit(c = *yyInput++); )
  20045. X        yylval.Number = 10 * yylval.Number + c - '0';
  20046. X        yyInput--;
  20047. X        if (sign < 0)
  20048. X        yylval.Number = -yylval.Number;
  20049. X        return sign ? tSNUMBER : tUNUMBER;
  20050. X    }
  20051. X    if (isalpha(c)) {
  20052. X        for (p = buff; isalpha(c = *yyInput++) || c == '.'; )
  20053. X        if (p < &buff[sizeof buff - 1])
  20054. X            *p++ = c;
  20055. X        *p = '\0';
  20056. X        yyInput--;
  20057. X        return LookupWord(buff);
  20058. X    }
  20059. X    if (c != '(')
  20060. X        return *yyInput++;
  20061. X    Count = 0;
  20062. X    do {
  20063. X        c = *yyInput++;
  20064. X        if (c == '\0')
  20065. X        return c;
  20066. X        if (c == '(')
  20067. X        Count++;
  20068. X        else if (c == ')')
  20069. X        Count--;
  20070. X    } while (Count > 0);
  20071. X    }
  20072. X}
  20073. X
  20074. X
  20075. Xtime_t
  20076. Xget_date(p, now)
  20077. X    char        *p;
  20078. X    struct timeb    *now;
  20079. X{
  20080. X    struct tm        *tm;
  20081. X    struct timeb    ftz;
  20082. X    time_t        Start;
  20083. X    time_t        tod;
  20084. X
  20085. X    yyInput = p;
  20086. X    if (now == NULL) {
  20087. X        now = &ftz;
  20088. X#if    !defined(HAVE_FTIME)
  20089. X    (void)time(&ftz.time);
  20090. X    /* Set the timezone global. */
  20091. X    tzset();
  20092. X    {
  20093. X#if sgi
  20094. X        ftz.timezone = (int) _timezone / 60;
  20095. X#else /* not sgi */
  20096. X#ifdef __386BSD__
  20097. X        ftz.timezone = 0;
  20098. X#else /* neither sgi nor 386BSD */
  20099. X#if defined (USG)
  20100. X        extern time_t timezone;
  20101. X
  20102. X        ftz.timezone = (int) timezone / 60;
  20103. X#else /* neither sgi nor 386BSD nor USG */
  20104. X        struct timeval tv;
  20105. X        struct timezone tz;
  20106. X
  20107. X        gettimeofday (&tv, &tz);
  20108. X        ftz.timezone = (int) tz.tz_minuteswest;
  20109. X#endif /* neither sgi nor 386BSD nor USG */
  20110. X#endif /* neither sgi nor 386BSD */
  20111. X#endif /* not sgi */
  20112. X    }
  20113. X#else /* HAVE_FTIME */
  20114. X    (void)ftime(&ftz);
  20115. X#endif /* HAVE_FTIME */
  20116. X    }
  20117. X
  20118. X    tm = localtime(&now->time);
  20119. X    yyYear = tm->tm_year;
  20120. X    yyMonth = tm->tm_mon + 1;
  20121. X    yyDay = tm->tm_mday;
  20122. X    yyTimezone = now->timezone;
  20123. X    yyDSTmode = DSTmaybe;
  20124. X    yyHour = 0;
  20125. X    yyMinutes = 0;
  20126. X    yySeconds = 0;
  20127. X    yyMeridian = MER24;
  20128. X    yyRelSeconds = 0;
  20129. X    yyRelMonth = 0;
  20130. X    yyHaveDate = 0;
  20131. X    yyHaveDay = 0;
  20132. X    yyHaveRel = 0;
  20133. X    yyHaveTime = 0;
  20134. X    yyHaveZone = 0;
  20135. X
  20136. X    if (yyparse()
  20137. X     || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
  20138. X    return -1;
  20139. X
  20140. X    if (yyHaveDate || yyHaveTime || yyHaveDay) {
  20141. X    Start = Convert(yyMonth, yyDay, yyYear, yyHour, yyMinutes, yySeconds,
  20142. X            yyMeridian, yyDSTmode);
  20143. X    if (Start < 0)
  20144. X        return -1;
  20145. X    }
  20146. X    else {
  20147. X    Start = now->time;
  20148. X    if (!yyHaveRel)
  20149. X        Start -= ((tm->tm_hour * 60L + tm->tm_min) * 60L) + tm->tm_sec;
  20150. X    }
  20151. X
  20152. X    Start += yyRelSeconds;
  20153. X    Start += RelativeMonth(Start, yyRelMonth);
  20154. X
  20155. X    if (yyHaveDay && !yyHaveDate) {
  20156. X    tod = RelativeDate(Start, yyDayOrdinal, yyDayNumber);
  20157. X    Start += tod;
  20158. X    }
  20159. X
  20160. X    /* Have to do *something* with a legitimate -1 so it's distinguishable
  20161. X     * from the error return value.  (Alternately could set errno on error.) */
  20162. X    return Start == -1 ? 0 : Start;
  20163. X}
  20164. X
  20165. X
  20166. X#if    defined(TEST)
  20167. X
  20168. X/* ARGSUSED */
  20169. Xmain(ac, av)
  20170. X    int        ac;
  20171. X    char    *av[];
  20172. X{
  20173. X    char    buff[128];
  20174. X    time_t    d;
  20175. X
  20176. X    (void)printf("Enter date, or blank line to exit.\n\t> ");
  20177. X    (void)fflush(stdout);
  20178. X    while (gets(buff) && buff[0]) {
  20179. X    d = get_date(buff, (struct timeb *)NULL);
  20180. X    if (d == -1)
  20181. X        (void)printf("Bad format - couldn't convert.\n");
  20182. X    else
  20183. X        (void)printf("%s", ctime(&d));
  20184. X    (void)printf("\t> ");
  20185. X    (void)fflush(stdout);
  20186. X    }
  20187. X    exit(0);
  20188. X    /* NOTREACHED */
  20189. X}
  20190. X#endif    /* defined(TEST) */
  20191. END_OF_FILE
  20192. if test 46681 -ne `wc -c <'getdate.c'`; then
  20193.     echo shar: \"'getdate.c'\" unpacked with wrong size!
  20194. fi
  20195. # end of 'getdate.c'
  20196. fi
  20197. if test -f 'alloca.c' -a "${1}" != "-c" ; then 
  20198.   echo shar: Will not clobber existing file \"'alloca.c'\"
  20199. else
  20200. echo shar: Extracting \"'alloca.c'\" \(5356 characters\)
  20201. sed "s/^X//" >'alloca.c' <<'END_OF_FILE'
  20202. X/*
  20203. X    alloca -- (mostly) portable public-domain implementation -- D A Gwyn
  20204. X
  20205. X    last edit:    86/05/30    rms
  20206. X       include config.h, since on VMS it renames some symbols.
  20207. X       Use xmalloc instead of malloc.
  20208. X
  20209. X    This implementation of the PWB library alloca() function,
  20210. X    which is used to allocate space off the run-time stack so
  20211. X    that it is automatically reclaimed upon procedure exit, 
  20212. X    was inspired by discussions with J. Q. Johnson of Cornell.
  20213. X
  20214. X    It should work under any C implementation that uses an
  20215. X    actual procedure stack (as opposed to a linked list of
  20216. X    frames).  There are some preprocessor constants that can
  20217. X    be defined when compiling for your specific system, for
  20218. X    improved efficiency; however, the defaults should be okay.
  20219. X
  20220. X    The general concept of this implementation is to keep
  20221. X    track of all alloca()-allocated blocks, and reclaim any
  20222. X    that are found to be deeper in the stack than the current
  20223. X    invocation.  This heuristic does not reclaim storage as
  20224. X    soon as it becomes invalid, but it will do so eventually.
  20225. X
  20226. X    As a special case, alloca(0) reclaims storage without
  20227. X    allocating any.  It is a good idea to use alloca(0) in
  20228. X    your main control loop, etc. to force garbage collection.
  20229. X*/
  20230. X#ifndef lint
  20231. Xstatic char    SCCSid[] = "@(#)alloca.c    1.1";    /* for the "what" utility */
  20232. X#endif
  20233. X
  20234. X#ifdef HAVE_CONFIG_H
  20235. X#include "config.h"
  20236. X#endif
  20237. X
  20238. X#ifdef emacs
  20239. X#ifdef static
  20240. X/* actually, only want this if static is defined as ""
  20241. X   -- this is for usg, in which emacs must undefine static
  20242. X   in order to make unexec workable
  20243. X   */
  20244. X#ifndef STACK_DIRECTION
  20245. Xyou
  20246. Xlose
  20247. X-- must know STACK_DIRECTION at compile-time
  20248. X#endif /* STACK_DIRECTION undefined */
  20249. X#endif /* static */
  20250. X#endif /* emacs */
  20251. X
  20252. X#ifndef alloca  /* If compiling with GCC, this file's not needed.  */
  20253. X
  20254. X#ifdef __STDC__
  20255. Xtypedef void    *pointer;        /* generic pointer type */
  20256. X#else
  20257. Xtypedef char    *pointer;        /* generic pointer type */
  20258. X#endif
  20259. X
  20260. X#define    NULL    0            /* null pointer constant */
  20261. X
  20262. Xextern void    free();
  20263. Xextern pointer    xmalloc();
  20264. X
  20265. X/*
  20266. X    Define STACK_DIRECTION if you know the direction of stack
  20267. X    growth for your system; otherwise it will be automatically
  20268. X    deduced at run-time.
  20269. X
  20270. X    STACK_DIRECTION > 0 => grows toward higher addresses
  20271. X    STACK_DIRECTION < 0 => grows toward lower addresses
  20272. X    STACK_DIRECTION = 0 => direction of growth unknown
  20273. X*/
  20274. X
  20275. X#ifndef STACK_DIRECTION
  20276. X#define    STACK_DIRECTION    0        /* direction unknown */
  20277. X#endif
  20278. X
  20279. X#if STACK_DIRECTION != 0
  20280. X
  20281. X#define    STACK_DIR    STACK_DIRECTION    /* known at compile-time */
  20282. X
  20283. X#else    /* STACK_DIRECTION == 0; need run-time code */
  20284. X
  20285. Xstatic int    stack_dir;        /* 1 or -1 once known */
  20286. X#define    STACK_DIR    stack_dir
  20287. X
  20288. Xstatic void
  20289. Xfind_stack_direction (/* void */)
  20290. X{
  20291. X  static char    *addr = NULL;    /* address of first
  20292. X                   `dummy', once known */
  20293. X  auto char    dummy;        /* to get stack address */
  20294. X
  20295. X  if (addr == NULL)
  20296. X    {                /* initial entry */
  20297. X      addr = &dummy;
  20298. X
  20299. X      find_stack_direction ();    /* recurse once */
  20300. X    }
  20301. X  else                /* second entry */
  20302. X    if (&dummy > addr)
  20303. X      stack_dir = 1;        /* stack grew upward */
  20304. X    else
  20305. X      stack_dir = -1;        /* stack grew downward */
  20306. X}
  20307. X
  20308. X#endif    /* STACK_DIRECTION == 0 */
  20309. X
  20310. X/*
  20311. X    An "alloca header" is used to:
  20312. X    (a) chain together all alloca()ed blocks;
  20313. X    (b) keep track of stack depth.
  20314. X
  20315. X    It is very important that sizeof(header) agree with malloc()
  20316. X    alignment chunk size.  The following default should work okay.
  20317. X*/
  20318. X
  20319. X#ifndef    ALIGN_SIZE
  20320. X#define    ALIGN_SIZE    sizeof(double)
  20321. X#endif
  20322. X
  20323. Xtypedef union hdr
  20324. X{
  20325. X  char    align[ALIGN_SIZE];    /* to force sizeof(header) */
  20326. X  struct
  20327. X    {
  20328. X      union hdr *next;        /* for chaining headers */
  20329. X      char *deep;        /* for stack depth measure */
  20330. X    } h;
  20331. X} header;
  20332. X
  20333. X/*
  20334. X    alloca( size ) returns a pointer to at least `size' bytes of
  20335. X    storage which will be automatically reclaimed upon exit from
  20336. X    the procedure that called alloca().  Originally, this space
  20337. X    was supposed to be taken from the current stack frame of the
  20338. X    caller, but that method cannot be made to work for some
  20339. X    implementations of C, for example under Gould's UTX/32.
  20340. X*/
  20341. X
  20342. Xstatic header *last_alloca_header = NULL; /* -> last alloca header */
  20343. X
  20344. Xpointer
  20345. Xalloca (size)            /* returns pointer to storage */
  20346. X     unsigned    size;        /* # bytes to allocate */
  20347. X{
  20348. X  auto char    probe;        /* probes stack depth: */
  20349. X  register char    *depth = &probe;
  20350. X
  20351. X#if STACK_DIRECTION == 0
  20352. X  if (STACK_DIR == 0)        /* unknown growth direction */
  20353. X    find_stack_direction ();
  20354. X#endif
  20355. X
  20356. X                /* Reclaim garbage, defined as all alloca()ed storage that
  20357. X                   was allocated from deeper in the stack than currently. */
  20358. X
  20359. X  {
  20360. X    register header    *hp;    /* traverses linked list */
  20361. X
  20362. X    for (hp = last_alloca_header; hp != NULL;)
  20363. X      if ((STACK_DIR > 0 && hp->h.deep > depth)
  20364. X      || (STACK_DIR < 0 && hp->h.deep < depth))
  20365. X    {
  20366. X      register header    *np = hp->h.next;
  20367. X
  20368. X      free ((pointer) hp);    /* collect garbage */
  20369. X
  20370. X      hp = np;        /* -> next header */
  20371. X    }
  20372. X      else
  20373. X    break;            /* rest are not deeper */
  20374. X
  20375. X    last_alloca_header = hp;    /* -> last valid storage */
  20376. X  }
  20377. X
  20378. X  if (size == 0)
  20379. X    return NULL;        /* no allocation required */
  20380. X
  20381. X  /* Allocate combined header + user data storage. */
  20382. X
  20383. X  {
  20384. X    register pointer    new = xmalloc (sizeof (header) + size);
  20385. X    /* address of header */
  20386. X
  20387. X    ((header *)new)->h.next = last_alloca_header;
  20388. X    ((header *)new)->h.deep = depth;
  20389. X
  20390. X    last_alloca_header = (header *)new;
  20391. X
  20392. X    /* User storage begins just after header. */
  20393. X
  20394. X    return (pointer)((char *)new + sizeof(header));
  20395. X  }
  20396. X}
  20397. X
  20398. X#endif /* no alloca */
  20399. END_OF_FILE
  20400. if test 5356 -ne `wc -c <'alloca.c'`; then
  20401.     echo shar: \"'alloca.c'\" unpacked with wrong size!
  20402. fi
  20403. # end of 'alloca.c'
  20404. fi
  20405. if test -f 'README' -a "${1}" != "-c" ; then 
  20406.   echo shar: Will not clobber existing file \"'README'\"
  20407. else
  20408. echo shar: Extracting \"'README'\" \(1839 characters\)
  20409. sed "s/^X//" >'README' <<'END_OF_FILE'
  20410. XHey!  Emacs!  Yo!  This is -*- Text -*- !!!
  20411. X
  20412. XThis GNU tar 1.11.2.  Please send bug reports, etc., to
  20413. Xbug-gnu-utils@prep.ai.mit.edu.  This is a beta-test release.  Please
  20414. Xtry it out.  There is no manual; the release of version 1.12 will
  20415. Xcontain a manual.
  20416. X
  20417. XGNU tar is based heavily on John Gilmore's public domain tar, but with
  20418. Xadded features.  The manual is currently being written.  
  20419. X
  20420. XThis distribution also includes rmt, the remote tape server (which
  20421. Xnormally must reside in /etc).  The mt tape drive control program is
  20422. Xin the GNU cpio distribution.
  20423. X
  20424. XSee the file INSTALL for compilation and installation instructions for Unix.
  20425. XSee the file NEWS for information on all that is new in this version
  20426. Xof tar.
  20427. X
  20428. Xmakefile.pc is a makefile for Turbo C 2.0 on MS-DOS.
  20429. X
  20430. XVarious people have been having problems using floppies on a NeXT.  In
  20431. Xorder to have them work right, you need to kill the automounting
  20432. Xprogram which tries to monut floppies as soon as they are added.
  20433. X
  20434. XIf you want to do incremental dumps, use the distributed backup
  20435. Xscripts.  They are what we use at the FSF to do all our backups.  Most
  20436. Ximportantly, do not use --incremental (-G) or --after-date (-N) or
  20437. X--newer-mtime to do incremental dumps.  The only option that works
  20438. Xcorrectly for this purpose is --listed-incremental.  (When extracting
  20439. Xincremental dumps, use --incremental (-G).)
  20440. X
  20441. XIf your system needs to link with -lPW to get alloca, but has
  20442. Xrename in the C library (so HAVE_RENAME is defined), -lPW might
  20443. Xgive you an incorrect version of rename.  On HP-UX this manifests
  20444. Xitself as an undefined data symbol called "Error" when linking cp, ln,
  20445. Xand mv.  If this happens, use `ar x' to extract alloca.o from libPW.a
  20446. Xand `ar rc' to put it in a library liballoca.a, and put that in LIBS
  20447. Xinstead of -lPW.  This problem does not occur when using gcc, which
  20448. Xhas alloca built in.
  20449. X
  20450. END_OF_FILE
  20451. if test 1839 -ne `wc -c <'README'`; then
  20452.     echo shar: \"'README'\" unpacked with wrong size!
  20453. fi
  20454. # end of 'README'
  20455. fi
  20456. if test -f 'INSTALL' -a "${1}" != "-c" ; then 
  20457.   echo shar: Will not clobber existing file \"'INSTALL'\"
  20458. else
  20459. echo shar: Extracting \"'INSTALL'\" \(5733 characters\)
  20460. sed "s/^X//" >'INSTALL' <<'END_OF_FILE'
  20461. XThis is a generic INSTALL file for utilities distributions.
  20462. XIf this package does not come with, e.g., installable documentation or
  20463. Xdata files, please ignore the references to them below.
  20464. X
  20465. XTo compile this package:
  20466. X
  20467. X1.  Configure the package for your system.  In the directory that this
  20468. Xfile is in, type `./configure'.  If you're using `csh' on an old
  20469. Xversion of System V, you might need to type `sh configure' instead to
  20470. Xprevent `csh' from trying to execute `configure' itself.
  20471. X
  20472. XThe `configure' shell script attempts to guess correct values for
  20473. Xvarious system-dependent variables used during compilation, and
  20474. Xcreates the Makefile(s) (one in each subdirectory of the source
  20475. Xdirectory).  In some packages it creates a C header file containing
  20476. Xsystem-dependent definitions.  It also creates a file `config.status'
  20477. Xthat you can run in the future to recreate the current configuration.
  20478. X
  20479. XRunning `configure' takes a minute or two.  While it is running, it
  20480. Xprints some messages that tell what it is doing.  If you don't want to
  20481. Xsee the messages, run `configure' with its standard output redirected
  20482. Xto `/dev/null'; for example, `./configure >/dev/null'.
  20483. X
  20484. XTo compile the package in a different directory from the one
  20485. Xcontaining the source code, you must use a version of `make' that
  20486. Xsupports the VPATH variable, such as GNU `make'.  `cd' to the directory
  20487. Xwhere you want the object files and executables to go and run
  20488. X`configure'.  `configure' automatically checks for the source code in
  20489. Xthe directory that `configure' is in and in `..'.  If for some reason
  20490. X`configure' is not in the source code directory that you are
  20491. Xconfiguring, then it will report that it can't find the source code.
  20492. XIn that case, run `configure' with the option `--srcdir=DIR', where
  20493. XDIR is the directory that contains the source code.
  20494. X
  20495. XBy default, `make install' will install the package's files in
  20496. X/usr/local/bin, /usr/local/lib, /usr/local/man, etc.  You can specify
  20497. Xan installation prefix other than /usr/local by giving `configure' the
  20498. Xoption `--prefix=PATH'.  Alternately, you can do so by giving a value
  20499. Xfor the `prefix' variable when you run `make', e.g.,
  20500. X    make prefix=/usr/gnu
  20501. X
  20502. XYou can specify separate installation prefixes for
  20503. Xarchitecture-specific files and architecture-independent files.  If
  20504. Xyou give `configure' the option `--exec-prefix=PATH' or set the
  20505. X`make' variable `exec_prefix' to PATH, the package will use PATH as
  20506. Xthe prefix for installing programs and libraries.  Data files and
  20507. Xdocumentation will still use the regular prefix.  Normally, all files
  20508. Xare installed using the regular prefix.
  20509. X
  20510. XAnother `configure' option is useful mainly in `Makefile' rules for
  20511. Xupdating `config.status' and `Makefile'.  The `--no-create' option
  20512. Xfigures out the configuration for your system and records it in
  20513. X`config.status', without actually configuring the package (creating
  20514. X`Makefile's and perhaps a configuration header file).  Later, you can
  20515. Xrun `./config.status' to actually configure the package.  You can also
  20516. Xgive `config.status' the `--recheck' option, which makes it re-run
  20517. X`configure' with the same arguments you used before.  This option is
  20518. Xuseful if you change `configure'.
  20519. X
  20520. XSome packages pay attention to `--with-PACKAGE' options to `configure',
  20521. Xwhere PACKAGE is something like `gnu-libc' or `x' (for the X Window System).
  20522. XThe README should mention any --with- options that the package recognizes.
  20523. X
  20524. X`configure' ignores any other arguments that you give it.
  20525. X
  20526. XIf your system requires unusual options for compilation or linking
  20527. Xthat `configure' doesn't know about, you can give `configure' initial
  20528. Xvalues for some variables by setting them in the environment.  In
  20529. XBourne-compatible shells, you can do that on the command line like
  20530. Xthis:
  20531. X    CC='gcc -traditional' DEFS=-D_POSIX_SOURCE ./configure
  20532. X
  20533. XThe `make' variables that you might want to override with environment
  20534. Xvariables when running `configure' are:
  20535. X
  20536. X(For these variables, any value given in the environment overrides the
  20537. Xvalue that `configure' would choose:)
  20538. XCC        C compiler program.
  20539. X        Default is `cc', or `gcc' if `gcc' is in your PATH.
  20540. XINSTALL        Program to use to install files.
  20541. X        Default is `install' if you have it, `cp' otherwise.
  20542. X
  20543. X(For these variables, any value given in the environment is added to
  20544. Xthe value that `configure' chooses:)
  20545. XDEFS        Configuration options, in the form `-Dfoo -Dbar ...'
  20546. X        Do not use this variable in packages that create a
  20547. X        configuration header file.
  20548. XLIBS        Libraries to link with, in the form `-lfoo -lbar ...'
  20549. X
  20550. XIf you need to do unusual things to compile the package, we encourage
  20551. Xyou to figure out how `configure' could check whether to do them, and
  20552. Xmail diffs or instructions to the address given in the README so we
  20553. Xcan include them in the next release.
  20554. X
  20555. X2.  Type `make' to compile the package.  If you want, you can override
  20556. Xthe `make' variables CFLAGS and LDFLAGS like this:
  20557. X
  20558. X    make CFLAGS=-O2 LDFLAGS=-s
  20559. X
  20560. X3.  If the package comes with self-tests and you want to run them,
  20561. Xtype `make check'.  If you're not sure whether there are any, try it;
  20562. Xif `make' responds with something like
  20563. X    make: *** No way to make target `check'.  Stop.
  20564. Xthen the package does not come with self-tests.
  20565. X
  20566. X4.  Type `make install' to install programs, data files, and
  20567. Xdocumentation.
  20568. X
  20569. X5.  You can remove the program binaries and object files from the
  20570. Xsource directory by typing `make clean'.  To also remove the
  20571. XMakefile(s), the header file containing system-dependent definitions
  20572. X(if the package uses one), and `config.status' (all the files that
  20573. X`configure' created), type `make distclean'.
  20574. X
  20575. XThe file `configure.in' is used as a template to create `configure' by
  20576. Xa program called `autoconf'.  You will only need it if you want to
  20577. Xregenerate `configure' using a newer version of `autoconf'.
  20578. END_OF_FILE
  20579. if test 5733 -ne `wc -c <'INSTALL'`; then
  20580.     echo shar: \"'INSTALL'\" unpacked with wrong size!
  20581. fi
  20582. # end of 'INSTALL'
  20583. fi
  20584. if test -f 'NEWS' -a "${1}" != "-c" ; then 
  20585.   echo shar: Will not clobber existing file \"'NEWS'\"
  20586. else
  20587. echo shar: Extracting \"'NEWS'\" \(3859 characters\)
  20588. sed "s/^X//" >'NEWS' <<'END_OF_FILE'
  20589. XCurrent Version: 1.11.2
  20590. X
  20591. X
  20592. XUser-visible changes since 1.11.1:
  20593. X
  20594. Xo Changes in backup scripts
  20595. X  - cleaned up considerably; notices error conditions better over rsh
  20596. X  - DUMP_REMIND_SCRIPT is now an option in backup-specs
  20597. X  - new file dump-remind is an example of a DUMP_REMIND_SCRIPT
  20598. Xo Superfluous "Reading dirname" was a bug; fixed.
  20599. Xo Incompatibility problems with a bug on Solaris are fixed.
  20600. Xo New option --gzip (aliases are --ungzip and -z); calls gzip instead
  20601. X  of compress.  Also, --use-compress-program lets you specify any
  20602. X  compress program.  --compress-block is renamed --block-compress and
  20603. X  now requires one of the three compression options to be specified.
  20604. Xo Several error messages are cleaned up.
  20605. Xo Directory owners are now set properly when running as root.
  20606. Xo Provide DUMP_REMIND_SCRIPT in backup-specs as a possible option 
  20607. X  for --info-script.
  20608. Xo Behave better with broken rmt servers.
  20609. Xo Dump scripts no longer use --atime-preserve; this causes a nasty probem.
  20610. Xo Several Makefile cleanups.
  20611. X
  20612. X
  20613. X==============
  20614. XVersion 1.11.1
  20615. XUser-visible changes since 1.11:
  20616. X
  20617. Xo Many bug fixes
  20618. X
  20619. X
  20620. X============
  20621. XVersion 1.11
  20622. XUser-visible changes since 1.10:
  20623. X
  20624. Xo Many bug fixes
  20625. X
  20626. Xo Now uses GNU standard configure, generated by Autoconf.
  20627. X
  20628. Xo Long options now use `--'; use of `+' is deprecated and support for it
  20629. X  will eventually be removed.
  20630. X
  20631. Xo New option --null causes filenames read by -T to be null-terminated,
  20632. X  and causes -C to be ignored.
  20633. X
  20634. Xo New option --remove-files deletes files (but not directories) after
  20635. X  they are added to the archive.
  20636. X
  20637. Xo New option --ignore-failed-read prevents read-errors from affecting
  20638. X  the exit status.
  20639. X
  20640. Xo New option --checkpoint prints occasional messages as the tape is
  20641. X  being read or written.
  20642. X
  20643. Xo New option --show-omitted-dirs prints the names of directories
  20644. X  omitted from the archive.
  20645. X
  20646. Xo Some tape drives which use a non-standard method of indicating
  20647. X  end-of-tape now work correctly with multi-tape archives.
  20648. X
  20649. Xo --volno-file: Read the volume number used in prompting the user (but
  20650. X  not in recording volume ID's on the archive) from a file.
  20651. X
  20652. Xo When using --multi-volume, you can now give multiple -f arguments;
  20653. X  the various tape drives will get used in sequence and then wrap
  20654. X  around to the beginning.
  20655. X
  20656. Xo Remote archive names no longer have to be in /dev: any file with a
  20657. X  `:' is interpreted as remote.  If new option --force-local is given,
  20658. X  then even archive files with a `:' are considered local.
  20659. X
  20660. Xo New option --atime-preserve restores (if possible) atimes to their
  20661. X  original values after dumping the file.
  20662. X
  20663. Xo No longer does tar confusingly dump "." when you don't tell it what
  20664. X  to dump.
  20665. X
  20666. Xo When extracting directories, tar now correctly restores their
  20667. X  modification and access times.
  20668. X
  20669. Xo Longnames support is redone differently--long name info directly
  20670. X  precedes the long-named file or link in the archive, so you no
  20671. X  longer have to wait for the extract to hit the end of the tape for
  20672. X  long names to work.
  20673. X
  20674. X
  20675. X=============
  20676. XVersion 1.10:
  20677. XUser-visible changes since 1.09:
  20678. X
  20679. XFilename to -G is optional.  -C works right.  
  20680. XNames +newer and +newer-mtime work right.
  20681. X
  20682. X-g is now +incremental
  20683. X-G is now +listed-incremental
  20684. X
  20685. XSparse files now work correctly.
  20686. X
  20687. X+volume is now called +label.
  20688. X
  20689. X+exclude now takes a filename argument, and +exclude-from does what
  20690. X+exclude used to do.
  20691. X
  20692. XExit status is now correct.
  20693. X
  20694. X+totals keeps track of total I/O and prints it when tar exits.
  20695. X
  20696. XWhen using +label with +extract, the label is now a regexp.
  20697. X
  20698. XNew option +tape-length (-L) does multi-volume handling like BSD dump:
  20699. Xyou tell tar how big the tape is and it will prompt at that point
  20700. Xinstead of waiting for a write error.
  20701. X
  20702. XNew backup scripts level-0 and level-1 which might be useful to
  20703. Xpeople.  They use a file "backup-specs" for information, and shouldn't
  20704. Xneed local modification.  These are what we use to do all our backups
  20705. Xat the FSF.
  20706. END_OF_FILE
  20707. if test 3859 -ne `wc -c <'NEWS'`; then
  20708.     echo shar: \"'NEWS'\" unpacked with wrong size!
  20709. fi
  20710. # end of 'NEWS'
  20711. fi
  20712. if test -f 'COPYING' -a "${1}" != "-c" ; then 
  20713.   echo shar: Will not clobber existing file \"'COPYING'\"
  20714. else
  20715. echo shar: Extracting \"'COPYING'\" \(17982 characters\)
  20716. sed "s/^X//" >'COPYING' <<'END_OF_FILE'
  20717. X            GNU GENERAL PUBLIC LICENSE
  20718. X               Version 2, June 1991
  20719. X
  20720. X Copyright (C) 1989, 1991 Free Software Foundation, Inc.
  20721. X                          675 Mass Ave, Cambridge, MA 02139, USA
  20722. X Everyone is permitted to copy and distribute verbatim copies
  20723. X of this license document, but changing it is not allowed.
  20724. X
  20725. X                Preamble
  20726. X
  20727. X  The licenses for most software are designed to take away your
  20728. Xfreedom to share and change it.  By contrast, the GNU General Public
  20729. XLicense is intended to guarantee your freedom to share and change free
  20730. Xsoftware--to make sure the software is free for all its users.  This
  20731. XGeneral Public License applies to most of the Free Software
  20732. XFoundation's software and to any other program whose authors commit to
  20733. Xusing it.  (Some other Free Software Foundation software is covered by
  20734. Xthe GNU Library General Public License instead.)  You can apply it to
  20735. Xyour programs, too.
  20736. X
  20737. X  When we speak of free software, we are referring to freedom, not
  20738. Xprice.  Our General Public Licenses are designed to make sure that you
  20739. Xhave the freedom to distribute copies of free software (and charge for
  20740. Xthis service if you wish), that you receive source code or can get it
  20741. Xif you want it, that you can change the software or use pieces of it
  20742. Xin new free programs; and that you know you can do these things.
  20743. X
  20744. X  To protect your rights, we need to make restrictions that forbid
  20745. Xanyone to deny you these rights or to ask you to surrender the rights.
  20746. XThese restrictions translate to certain responsibilities for you if you
  20747. Xdistribute copies of the software, or if you modify it.
  20748. X
  20749. X  For example, if you distribute copies of such a program, whether
  20750. Xgratis or for a fee, you must give the recipients all the rights that
  20751. Xyou have.  You must make sure that they, too, receive or can get the
  20752. Xsource code.  And you must show them these terms so they know their
  20753. Xrights.
  20754. X
  20755. X  We protect your rights with two steps: (1) copyright the software, and
  20756. X(2) offer you this license which gives you legal permission to copy,
  20757. Xdistribute and/or modify the software.
  20758. X
  20759. X  Also, for each author's protection and ours, we want to make certain
  20760. Xthat everyone understands that there is no warranty for this free
  20761. Xsoftware.  If the software is modified by someone else and passed on, we
  20762. Xwant its recipients to know that what they have is not the original, so
  20763. Xthat any problems introduced by others will not reflect on the original
  20764. Xauthors' reputations.
  20765. X
  20766. X  Finally, any free program is threatened constantly by software
  20767. Xpatents.  We wish to avoid the danger that redistributors of a free
  20768. Xprogram will individually obtain patent licenses, in effect making the
  20769. Xprogram proprietary.  To prevent this, we have made it clear that any
  20770. Xpatent must be licensed for everyone's free use or not licensed at all.
  20771. X
  20772. X  The precise terms and conditions for copying, distribution and
  20773. Xmodification follow.
  20774. X
  20775. X            GNU GENERAL PUBLIC LICENSE
  20776. X   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
  20777. X
  20778. X  0. This License applies to any program or other work which contains
  20779. Xa notice placed by the copyright holder saying it may be distributed
  20780. Xunder the terms of this General Public License.  The "Program", below,
  20781. Xrefers to any such program or work, and a "work based on the Program"
  20782. Xmeans either the Program or any derivative work under copyright law:
  20783. Xthat is to say, a work containing the Program or a portion of it,
  20784. Xeither verbatim or with modifications and/or translated into another
  20785. Xlanguage.  (Hereinafter, translation is included without limitation in
  20786. Xthe term "modification".)  Each licensee is addressed as "you".
  20787. X
  20788. XActivities other than copying, distribution and modification are not
  20789. Xcovered by this License; they are outside its scope.  The act of
  20790. Xrunning the Program is not restricted, and the output from the Program
  20791. Xis covered only if its contents constitute a work based on the
  20792. XProgram (independent of having been made by running the Program).
  20793. XWhether that is true depends on what the Program does.
  20794. X
  20795. X  1. You may copy and distribute verbatim copies of the Program's
  20796. Xsource code as you receive it, in any medium, provided that you
  20797. Xconspicuously and appropriately publish on each copy an appropriate
  20798. Xcopyright notice and disclaimer of warranty; keep intact all the
  20799. Xnotices that refer to this License and to the absence of any warranty;
  20800. Xand give any other recipients of the Program a copy of this License
  20801. Xalong with the Program.
  20802. X
  20803. XYou may charge a fee for the physical act of transferring a copy, and
  20804. Xyou may at your option offer warranty protection in exchange for a fee.
  20805. X
  20806. X  2. You may modify your copy or copies of the Program or any portion
  20807. Xof it, thus forming a work based on the Program, and copy and
  20808. Xdistribute such modifications or work under the terms of Section 1
  20809. Xabove, provided that you also meet all of these conditions:
  20810. X
  20811. X    a) You must cause the modified files to carry prominent notices
  20812. X    stating that you changed the files and the date of any change.
  20813. X
  20814. X    b) You must cause any work that you distribute or publish, that in
  20815. X    whole or in part contains or is derived from the Program or any
  20816. X    part thereof, to be licensed as a whole at no charge to all third
  20817. X    parties under the terms of this License.
  20818. X
  20819. X    c) If the modified program normally reads commands interactively
  20820. X    when run, you must cause it, when started running for such
  20821. X    interactive use in the most ordinary way, to print or display an
  20822. X    announcement including an appropriate copyright notice and a
  20823. X    notice that there is no warranty (or else, saying that you provide
  20824. X    a warranty) and that users may redistribute the program under
  20825. X    these conditions, and telling the user how to view a copy of this
  20826. X    License.  (Exception: if the Program itself is interactive but
  20827. X    does not normally print such an announcement, your work based on
  20828. X    the Program is not required to print an announcement.)
  20829. X
  20830. XThese requirements apply to the modified work as a whole.  If
  20831. Xidentifiable sections of that work are not derived from the Program,
  20832. Xand can be reasonably considered independent and separate works in
  20833. Xthemselves, then this License, and its terms, do not apply to those
  20834. Xsections when you distribute them as separate works.  But when you
  20835. Xdistribute the same sections as part of a whole which is a work based
  20836. Xon the Program, the distribution of the whole must be on the terms of
  20837. Xthis License, whose permissions for other licensees extend to the
  20838. Xentire whole, and thus to each and every part regardless of who wrote it.
  20839. X
  20840. XThus, it is not the intent of this section to claim rights or contest
  20841. Xyour rights to work written entirely by you; rather, the intent is to
  20842. Xexercise the right to control the distribution of derivative or
  20843. Xcollective works based on the Program.
  20844. X
  20845. XIn addition, mere aggregation of another work not based on the Program
  20846. Xwith the Program (or with a work based on the Program) on a volume of
  20847. Xa storage or distribution medium does not bring the other work under
  20848. Xthe scope of this License.
  20849. X
  20850. X  3. You may copy and distribute the Program (or a work based on it,
  20851. Xunder Section 2) in object code or executable form under the terms of
  20852. XSections 1 and 2 above provided that you also do one of the following:
  20853. X
  20854. X    a) Accompany it with the complete corresponding machine-readable
  20855. X    source code, which must be distributed under the terms of Sections
  20856. X    1 and 2 above on a medium customarily used for software interchange; or,
  20857. X
  20858. X    b) Accompany it with a written offer, valid for at least three
  20859. X    years, to give any third party, for a charge no more than your
  20860. X    cost of physically performing source distribution, a complete
  20861. X    machine-readable copy of the corresponding source code, to be
  20862. X    distributed under the terms of Sections 1 and 2 above on a medium
  20863. X    customarily used for software interchange; or,
  20864. X
  20865. X    c) Accompany it with the information you received as to the offer
  20866. X    to distribute corresponding source code.  (This alternative is
  20867. X    allowed only for noncommercial distribution and only if you
  20868. X    received the program in object code or executable form with such
  20869. X    an offer, in accord with Subsection b above.)
  20870. X
  20871. XThe source code for a work means the preferred form of the work for
  20872. Xmaking modifications to it.  For an executable work, complete source
  20873. Xcode means all the source code for all modules it contains, plus any
  20874. Xassociated interface definition files, plus the scripts used to
  20875. Xcontrol compilation and installation of the executable.  However, as a
  20876. Xspecial exception, the source code distributed need not include
  20877. Xanything that is normally distributed (in either source or binary
  20878. Xform) with the major components (compiler, kernel, and so on) of the
  20879. Xoperating system on which the executable runs, unless that component
  20880. Xitself accompanies the executable.
  20881. X
  20882. XIf distribution of executable or object code is made by offering
  20883. Xaccess to copy from a designated place, then offering equivalent
  20884. Xaccess to copy the source code from the same place counts as
  20885. Xdistribution of the source code, even though third parties are not
  20886. Xcompelled to copy the source along with the object code.
  20887. X
  20888. X  4. You may not copy, modify, sublicense, or distribute the Program
  20889. Xexcept as expressly provided under this License.  Any attempt
  20890. Xotherwise to copy, modify, sublicense or distribute the Program is
  20891. Xvoid, and will automatically terminate your rights under this License.
  20892. XHowever, parties who have received copies, or rights, from you under
  20893. Xthis License will not have their licenses terminated so long as such
  20894. Xparties remain in full compliance.
  20895. X
  20896. X  5. You are not required to accept this License, since you have not
  20897. Xsigned it.  However, nothing else grants you permission to modify or
  20898. Xdistribute the Program or its derivative works.  These actions are
  20899. Xprohibited by law if you do not accept this License.  Therefore, by
  20900. Xmodifying or distributing the Program (or any work based on the
  20901. XProgram), you indicate your acceptance of this License to do so, and
  20902. Xall its terms and conditions for copying, distributing or modifying
  20903. Xthe Program or works based on it.
  20904. X
  20905. X  6. Each time you redistribute the Program (or any work based on the
  20906. XProgram), the recipient automatically receives a license from the
  20907. Xoriginal licensor to copy, distribute or modify the Program subject to
  20908. Xthese terms and conditions.  You may not impose any further
  20909. Xrestrictions on the recipients' exercise of the rights granted herein.
  20910. XYou are not responsible for enforcing compliance by third parties to
  20911. Xthis License.
  20912. X
  20913. X  7. If, as a consequence of a court judgment or allegation of patent
  20914. Xinfringement or for any other reason (not limited to patent issues),
  20915. Xconditions are imposed on you (whether by court order, agreement or
  20916. Xotherwise) that contradict the conditions of this License, they do not
  20917. Xexcuse you from the conditions of this License.  If you cannot
  20918. Xdistribute so as to satisfy simultaneously your obligations under this
  20919. XLicense and any other pertinent obligations, then as a consequence you
  20920. Xmay not distribute the Program at all.  For example, if a patent
  20921. Xlicense would not permit royalty-free redistribution of the Program by
  20922. Xall those who receive copies directly or indirectly through you, then
  20923. Xthe only way you could satisfy both it and this License would be to
  20924. Xrefrain entirely from distribution of the Program.
  20925. X
  20926. XIf any portion of this section is held invalid or unenforceable under
  20927. Xany particular circumstance, the balance of the section is intended to
  20928. Xapply and the section as a whole is intended to apply in other
  20929. Xcircumstances.
  20930. X
  20931. XIt is not the purpose of this section to induce you to infringe any
  20932. Xpatents or other property right claims or to contest validity of any
  20933. Xsuch claims; this section has the sole purpose of protecting the
  20934. Xintegrity of the free software distribution system, which is
  20935. Ximplemented by public license practices.  Many people have made
  20936. Xgenerous contributions to the wide range of software distributed
  20937. Xthrough that system in reliance on consistent application of that
  20938. Xsystem; it is up to the author/donor to decide if he or she is willing
  20939. Xto distribute software through any other system and a licensee cannot
  20940. Ximpose that choice.
  20941. X
  20942. XThis section is intended to make thoroughly clear what is believed to
  20943. Xbe a consequence of the rest of this License.
  20944. X
  20945. X  8. If the distribution and/or use of the Program is restricted in
  20946. Xcertain countries either by patents or by copyrighted interfaces, the
  20947. Xoriginal copyright holder who places the Program under this License
  20948. Xmay add an explicit geographical distribution limitation excluding
  20949. Xthose countries, so that distribution is permitted only in or among
  20950. Xcountries not thus excluded.  In such case, this License incorporates
  20951. Xthe limitation as if written in the body of this License.
  20952. X
  20953. X  9. The Free Software Foundation may publish revised and/or new versions
  20954. Xof the General Public License from time to time.  Such new versions will
  20955. Xbe similar in spirit to the present version, but may differ in detail to
  20956. Xaddress new problems or concerns.
  20957. X
  20958. XEach version is given a distinguishing version number.  If the Program
  20959. Xspecifies a version number of this License which applies to it and "any
  20960. Xlater version", you have the option of following the terms and conditions
  20961. Xeither of that version or of any later version published by the Free
  20962. XSoftware Foundation.  If the Program does not specify a version number of
  20963. Xthis License, you may choose any version ever published by the Free Software
  20964. XFoundation.
  20965. X
  20966. X  10. If you wish to incorporate parts of the Program into other free
  20967. Xprograms whose distribution conditions are different, write to the author
  20968. Xto ask for permission.  For software which is copyrighted by the Free
  20969. XSoftware Foundation, write to the Free Software Foundation; we sometimes
  20970. Xmake exceptions for this.  Our decision will be guided by the two goals
  20971. Xof preserving the free status of all derivatives of our free software and
  20972. Xof promoting the sharing and reuse of software generally.
  20973. X
  20974. X                NO WARRANTY
  20975. X
  20976. X  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
  20977. XFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
  20978. XOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
  20979. XPROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
  20980. XOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  20981. XMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
  20982. XTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
  20983. XPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
  20984. XREPAIR OR CORRECTION.
  20985. X
  20986. X  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
  20987. XWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
  20988. XREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
  20989. XINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
  20990. XOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
  20991. XTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
  20992. XYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
  20993. XPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
  20994. XPOSSIBILITY OF SUCH DAMAGES.
  20995. X
  20996. X             END OF TERMS AND CONDITIONS
  20997. X
  20998. X    Appendix: How to Apply These Terms to Your New Programs
  20999. X
  21000. X  If you develop a new program, and you want it to be of the greatest
  21001. Xpossible use to the public, the best way to achieve this is to make it
  21002. Xfree software which everyone can redistribute and change under these terms.
  21003. X
  21004. X  To do so, attach the following notices to the program.  It is safest
  21005. Xto attach them to the start of each source file to most effectively
  21006. Xconvey the exclusion of warranty; and each file should have at least
  21007. Xthe "copyright" line and a pointer to where the full notice is found.
  21008. X
  21009. X    <one line to give the program's name and a brief idea of what it does.>
  21010. X    Copyright (C) 19yy  <name of author>
  21011. X
  21012. X    This program is free software; you can redistribute it and/or modify
  21013. X    it under the terms of the GNU General Public License as published by
  21014. X    the Free Software Foundation; either version 2 of the License, or
  21015. X    (at your option) any later version.
  21016. X
  21017. X    This program is distributed in the hope that it will be useful,
  21018. X    but WITHOUT ANY WARRANTY; without even the implied warranty of
  21019. X    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21020. X    GNU General Public License for more details.
  21021. X
  21022. X    You should have received a copy of the GNU General Public License
  21023. X    along with this program; if not, write to the Free Software
  21024. X    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  21025. X
  21026. XAlso add information on how to contact you by electronic and paper mail.
  21027. X
  21028. XIf the program is interactive, make it output a short notice like this
  21029. Xwhen it starts in an interactive mode:
  21030. X
  21031. X    Gnomovision version 69, Copyright (C) 19yy name of author
  21032. X    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
  21033. X    This is free software, and you are welcome to redistribute it
  21034. X    under certain conditions; type `show c' for details.
  21035. X
  21036. XThe hypothetical commands `show w' and `show c' should show the appropriate
  21037. Xparts of the General Public License.  Of course, the commands you use may
  21038. Xbe called something other than `show w' and `show c'; they could even be
  21039. Xmouse-clicks or menu items--whatever suits your program.
  21040. X
  21041. XYou should also get your employer (if you work as a programmer) or your
  21042. Xschool, if any, to sign a "copyright disclaimer" for the program, if
  21043. Xnecessary.  Here is a sample; alter the names:
  21044. X
  21045. X  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  21046. X  `Gnomovision' (which makes passes at compilers) written by James Hacker.
  21047. X
  21048. X  <signature of Ty Coon>, 1 April 1989
  21049. X  Ty Coon, President of Vice
  21050. X
  21051. XThis General Public License does not permit incorporating your program into
  21052. Xproprietary programs.  If your program is a subroutine library, you may
  21053. Xconsider it more useful to permit linking proprietary applications with the
  21054. Xlibrary.  If this is what you want to do, use the GNU Library General
  21055. XPublic License instead of this License.
  21056. END_OF_FILE
  21057. if test 17982 -ne `wc -c <'COPYING'`; then
  21058.     echo shar: \"'COPYING'\" unpacked with wrong size!
  21059. fi
  21060. # end of 'COPYING'
  21061. fi
  21062. if test -f 'ChangeLog' -a "${1}" != "-c" ; then 
  21063.   echo shar: Will not clobber existing file \"'ChangeLog'\"
  21064. else
  21065. echo shar: Extracting \"'ChangeLog'\" \(61978 characters\)
  21066. sed "s/^X//" >'ChangeLog' <<'END_OF_FILE'
  21067. XThu Mar 25 13:32:40 1993  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21068. X
  21069. X    * version.c: Released version 1.11.2.
  21070. X
  21071. X    * Makefile.in (dist): Do the link differently; some of the
  21072. X    files have changed filesystems which makes it more complex.
  21073. X
  21074. X    * Makefile.in (dist, shar): Use gzip instead of compress.
  21075. X
  21076. X    * create.c (dump_file): Test for curdev==-1, not curdev<0.
  21077. X    Some losing NFS systems give negative device numbers
  21078. X    sometimes.
  21079. X
  21080. XThu Mar 25 11:55:15 1993  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21081. X
  21082. X        * level-0, level-1 (TAR_PART1): Use `--block-size', not just
  21083. X          `--block', which is now ambiguous. 
  21084. X
  21085. XWed Mar 24 22:12:51 1993  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21086. X
  21087. X        * backup-specs (TAR): New variable.
  21088. X
  21089. X        * level-0, level-1 (TAR_PART1): Get path of GNU tar from `TAR'
  21090. X          variable, don't hardcode it.
  21091. X
  21092. XSat Mar 20 00:20:05 1993  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21093. X
  21094. X        * backup-specs (SLEEP_MESSAGE): put backslashes in front of nested
  21095. X          double quotes. 
  21096. X
  21097. X        * level-0, level-1 (BACKUP_DIRS): Don't put in quotes. 
  21098. X          (LOGFILE): Use sed to construct name, not awk. 
  21099. X
  21100. X        * dump-remind (recipients): Replaced inefficient pipeline with a
  21101. X          single, simple sed script. 
  21102. X          (volno): Deal with the possibility that VOLNO_FILE may not be
  21103. X          created yet. 
  21104. X
  21105. XFri Mar 19 15:05:15 1993  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21106. X
  21107. X    * backup-specs (VOLNO_FILE): Removed abusive comment by Noah.
  21108. X
  21109. X    * buffer.c (new_volume): Write the global volume number to the
  21110. X    volno file before running the info script, so that the script
  21111. X    can look at it.
  21112. X
  21113. XThu Mar 18 20:11:54 1993  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21114. X
  21115. X        * Makefile.in (AUX): Include `dump-remind' in distribution.
  21116. X
  21117. X        * backup-specs (SLEEP_MESSAGE): New variable.
  21118. X          level-0, level-1: Use it instead of external `dont_touch' file.
  21119. X
  21120. X        * level-0, level-1: Put most of the script in () and pipe
  21121. X          everything from the subshell through tee -a $LOGFILE.  Since you
  21122. X          really want most of the output to go to the logfile anyway, and
  21123. X          since all those pipelines were preventing one from getting the
  21124. X          exit status of most commands, this seems like the right idea.
  21125. X
  21126. X        * level-0, level-1 (LOGFILE): Use YYYY-MM-DD (all numeric) format
  21127. X          for log file name, since that makes the file names sortable in a
  21128. X          coherent way.  Suffix should always be `level-n' where n is the
  21129. X          dump level.  level-0 script was just using `-full' instead.
  21130. X
  21131. X        * level-0, level-1 (DUMP_LEVEL): New variable.  Set to `0' or `1'
  21132. X          in each script as appropriate.
  21133. X
  21134. X        * level-0, level-1 (HOST): Renamed to `localhost' for clarity.
  21135. X          (host): renamed to `remotehost' for clarity.
  21136. X
  21137. X        * level-0, level-1 (startdate): New variable.  Use it in Subject
  21138. X          line of mailed report.
  21139. X
  21140. X        * level-0, level-1: Fixed all instances where sed is called with a
  21141. X          script on the command line to use `-e' option.
  21142. X
  21143. X        * level-0, level-1: Don't try to call logfile.sed to filter
  21144. X          LOGFILE.  It's not distributed with tar and was never really used
  21145. X          anyway.
  21146. X
  21147. X        * level-0, level-1: Put quotes around most variable names (barring
  21148. X          those that are known to intentionally contain text that should be
  21149. X          expanded into multiple words, like `TAR_PART1').
  21150. X
  21151. X        * level-0, level-1: Got rid of annoying trailing backslashes in awk
  21152. X          scripts.  They were gratuitous.  Made them a little more readable
  21153. X          by adding some whitespace.
  21154. X
  21155. XWed Mar 17 10:30:58 1993  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21156. X
  21157. X    * tar.c (describe, long_options): Changed --compress-block to
  21158. X    --block-compress.  
  21159. X    (options): Fixed f_compress_block sanity check error message
  21160. X    to give the correct name of the option.
  21161. X
  21162. XTue Mar 16 14:52:40 1993  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21163. X
  21164. X    * extract.c (extract_archive): case LF_DIR: Do chown when
  21165. X    necessary.  Don't bother jumping to set_filestat for
  21166. X    f_modified; repeat the chmod code here.  Replace `break',
  21167. X    deleted on 2 September 1992.  
  21168. X
  21169. X    * tar.c (describe, long_options, options): Added gzip options
  21170. X    and use-compress-program option.  
  21171. X    * tar.h: Added new compression options.
  21172. X    * buffer.c (child_open, open_archive): Use new compression options.
  21173. X
  21174. X    * create.c (start_header): Only mask off high bits when 
  21175. X    creating old-style archives.
  21176. X    * list.c (decode_header): Mask off potentially misleading
  21177. X    high bits from the mode when reading headers.
  21178. X
  21179. XMon Mar 15 11:34:34 1993  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21180. X
  21181. X    * extract.c (extract_archive): Put arguments in the right
  21182. X    order for error message.
  21183. X
  21184. X    * create.c (deal_with_sparse): if the last byte was null, we
  21185. X    didn't write it out.
  21186. X
  21187. X    * gnu.c, create.c, extract.c, diffarch.c, list.c throughout:
  21188. X    Replace malloc calls with ck_malloc and realloc with ck_realloc.
  21189. X
  21190. X    * tar.c (describe): Improve doc for -L.
  21191. X
  21192. X    * tar.c (name_next): Don't apply exclusion to explicitly named
  21193. X    files.
  21194. X
  21195. X    * tar.c (long_options, describe): Added new-volume-script as
  21196. X    an alias for info-script.
  21197. X
  21198. X    * extract.c (extract_archive): LF_DUMPDIR case; misplaced paren.
  21199. X
  21200. X    * extract.c (extract_archive): extract_file case, first if, 
  21201. X    include space for null in namelen computation.
  21202. X
  21203. X    * extract.c (extract_sparse_file): Use value returned by write
  21204. X    to properly create error message.
  21205. X
  21206. X    * create.c (create_archive): Don't assume we have anything to
  21207. X    dump.
  21208. X
  21209. X    * buffer.c (open_archive): Set current_file_name for the
  21210. X    volume header so that verbose listings work properly.
  21211. X
  21212. X    * Makefile.in (realclean): Added getdate.c.
  21213. X
  21214. XThu Jan 14 23:38:44 1993  David J. MacKenzie  (djm@kropotkin.gnu.ai.mit.edu)
  21215. X
  21216. X    * tar.c: Include fnmatch.h after port.h to make sure we get our FNM_*
  21217. X    (e.g. on HPUX 8).
  21218. X
  21219. XTue Nov 24 08:30:54 1992  David J. MacKenzie  (djm@goldman.gnu.ai.mit.edu)
  21220. X
  21221. X    * tar.c (addname), gnu.c (read_dir_file): Use HAVE_GETCWD, not USG.
  21222. X
  21223. X    * port.h, rmt.h: Use HAVE_STRING_H, not USG.
  21224. X
  21225. X    * port.h: Add dir header decls.
  21226. X    * create.c, gnu.c: Use SYSNDIR, SYSDIR, and NDIR
  21227. X    instead of BSD42 and USG.  Rename DP_NAMELEN to NLENGTH.
  21228. X    Use `struct dirent' instead of `struct direct'.
  21229. X    * create.c, gnu.c, tar.c: Remove dir header decls.
  21230. X
  21231. XWed Nov 18 15:31:30 1992  David J. MacKenzie  (djm@goldman.gnu.ai.mit.edu)
  21232. X
  21233. X    * tar.c: Change FNM_TARPATH to FNM_LEADING_DIR to match change
  21234. X    in fnmatch.[ch].
  21235. X
  21236. XWed Oct 21 00:52:24 1992  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21237. X
  21238. X        * level-0, level-1: put curly braces around variables for clarity.
  21239. X
  21240. X        * backup-specs (DUMP_REMIND_SCRIPT): define it (but commented out
  21241. X          so that distributed dump scripts won't use it by default).
  21242. X          level-0, level-1 (TAR_PART1): use --info-script if
  21243. X          DUMP_REMIND_SCRIPT is defined.
  21244. X          dump-remind: new file (intended as an example).
  21245. X
  21246. XThu Oct 15 03:33:28 1992  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21247. X
  21248. X        * level-0, level-1: remove $LOGFILE.tmp files before exiting.
  21249. X
  21250. XFri Oct  2 00:28:01 1992  David J. MacKenzie  (djm@goldman.gnu.ai.mit.edu)
  21251. X
  21252. X    * tar.c (describe): Fix some tab alignments.
  21253. X
  21254. X    * Makefile.in (SRC3): Add getdate.c, for systems without bison/yacc
  21255. X    (like MS-DOS).
  21256. X
  21257. X    * diffarch.c (diff_sparse_files): Add missing arg to fprintf calls.
  21258. X
  21259. X    * extract.c (extract_archive, restore_saved_dir_info),
  21260. X    buffer.c (child_open), list.c (decode_header, print_header):
  21261. X    Delete unused vars.  
  21262. X
  21263. X    * port.c [__MSDOS__]: Have strstr, rename, and mkdir.  Don't
  21264. X    define ck_pipe.
  21265. X
  21266. X    * buffer.c, tar.c (init_volume_number, closeout_volume_number),
  21267. X    create.c (write_long):     Declare as void, not int, since they
  21268. X    don't return a value.
  21269. X
  21270. XThu Sep 24 00:06:02 1992  Michael I Bushnell  (mib@churchy.gnu.ai.mit.edu)
  21271. X
  21272. X    * level-0, level-1 (TAR_PART1): remove --atime-preserve
  21273. X    because of a total screw.
  21274. X
  21275. XTue Sep 22 14:15:48 1992  Michael I Bushnell  (mib@wookumz.gnu.ai.mit.edu)
  21276. X
  21277. X    * buffer.c (close_archive): Removed leftover `break' from when
  21278. X    this was a switch.
  21279. X
  21280. XTue Sep 22 08:33:16 1992  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21281. X
  21282. X        * create.c, port.h: indented #pragma directives with 1 space. 
  21283. X
  21284. XFri Sep 18 14:15:17 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21285. X
  21286. X    * All source files: re indented using GNU indent.  
  21287. X
  21288. X    * rtapelib.c (__rmt_read): Only read the amount left in the
  21289. X    buffer; otherwise a broken rmt server (which puts too much
  21290. X    data out) could overwrite past our buffer.
  21291. X
  21292. XThu Sep 17 14:08:58 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21293. X
  21294. X    * create.c: Throughout, use struct utimbuf rather than array
  21295. X    of longs.
  21296. X
  21297. X    * configure.in: Check for getpwuid and getgrgid.
  21298. X
  21299. X    * Makefile.in (SRC3, AUX): Move alloca.c to SRC3.
  21300. X    (OBJ3): Add @ALLOCA@.
  21301. X
  21302. X    * Makefile.in (getdate.c): Look in srcdir for getdate.y.
  21303. X
  21304. X    * buffer.c (close_archive): We can't check WTERMSIG
  21305. X    meaningfully unless we already know tha WIFSIGNALED is true.
  21306. X    (There is no guarantee it WTERMSIG will return zero when
  21307. X    WIFSIGNALED is false.)
  21308. X    * port.c (rmdir, mkdir): Check WIFSIGNALED rather than
  21309. X    WTERMSIG.
  21310. X
  21311. X    * Makefile.in (getdate.c): Use $(YACC) instead of `yacc'.
  21312. X
  21313. XTue Sep 15 14:49:48 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21314. X
  21315. X    * version.c: Released version 1.11.1.
  21316. X
  21317. X    * Makefile (AUX): Added NEWS.
  21318. X
  21319. X    * Makefile.in (rmt): Added $(LIBS).
  21320. X    * configure.in: Added tests for libraries needed on Solaris.
  21321. X
  21322. X    * mangle.c (extract_mangle): Null terminate link name for
  21323. X    losing archives missing it.
  21324. X
  21325. X    * Makefile.in: added target and rule for getdate.c: getdate.y;
  21326. X    some makes don't have one built in.
  21327. X
  21328. XMon Sep 14 16:23:15 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21329. X
  21330. X    * tar.c (options, main): Advise use of --help rather than
  21331. X    +help.
  21332. X
  21333. X    * create.c (write_long): Using hstat here is a Bad Idea, and
  21334. X    totally unnecessary at that.
  21335. X
  21336. X    * list.c (read_header): Compute both signed and normal
  21337. X    checksums.
  21338. X
  21339. X    * configure.in: Define BSD in the presence of /sdmach or 
  21340. X    /../../mach.
  21341. X
  21342. X    * diffarch.c, buffer.c: Declare valloc as void* rather than
  21343. X    char*.
  21344. X
  21345. X    * Makefile.in: Don't install info files.
  21346. X
  21347. X    * configure.in: Check for malloc was scrambled.
  21348. X
  21349. X    * port.h: Undefine index and rindex if necessary; some
  21350. X    string.h's define them for us.
  21351. X
  21352. X    * tar.c (addname): Missing braces after if.
  21353. X    * gnu.c (read_dir_file): Missing braces after if.
  21354. X
  21355. X    * names.c: Add include of <stdio.h>,
  21356. X
  21357. X    * create.c (start_header): Set current_file_name so that 
  21358. X    print_header (used for verbose create) works properly.
  21359. X    (dump_file): Set current_link_name when setting up symlink
  21360. X    and hardlink records.
  21361. X
  21362. XFri Sep 11 01:05:52 1992  David J. MacKenzie  (djm@nutrimat.gnu.ai.mit.edu)
  21363. X
  21364. X    * fnmatch.[ch]: New files.
  21365. X    * wildmat.c: File removed.
  21366. X    * tar.c: Include fnmatch.h and use fnmatch instead of wildmat.
  21367. X    * Makefile.in, makefile.pc: Replace wildmat.o(bj) with fnmatch.
  21368. X
  21369. XThu Sep 10 23:19:30 1992  David J. MacKenzie  (djm@nutrimat.gnu.ai.mit.edu)
  21370. X
  21371. X    * buffer.c, tar.c: Remove redundant decls of getenv, rindex.
  21372. X
  21373. X    * Makefile.in: Add uninstall target.
  21374. X    Define libdir instead of hardcoding /etc for installing rmt.
  21375. X
  21376. XThu Sep 10 13:06:03 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21377. X
  21378. X    * list.c (read_header): On second thought, that doesn't work
  21379. X    either, so just store the names in malloced areas.  Sigh.
  21380. X
  21381. X    * NEWS: New file.
  21382. X    * README: Removed things that belong in NEWS; point to it.
  21383. X
  21384. X    * list.c (read_header): current_file_name and
  21385. X    current_link_name need to be set to the arrays in head rather
  21386. X    than header; header is the actual read buffer and will change.
  21387. X
  21388. X    * extract.c (extract_archive):
  21389. X    * buffer.c (new_volume): `#' directives need to start in
  21390. X    column 1.
  21391. X
  21392. XThu Sep 10 06:09:18 1992  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21393. X
  21394. X        * level-0, level-1 (TAR_PART1): put --atime-preserve inside quotes.
  21395. X
  21396. XWed Sep  9 13:34:26 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21397. X
  21398. X    * Makefile.in (AUX): Add getpagesize.h.
  21399. X    (AUX): Comment out manuals.
  21400. X    (all): Comment out dependency on tar.info.
  21401. X
  21402. X    * version.c: Release of version 1.11.
  21403. X
  21404. X    * level-0, level-1 (TAR_PART1): Use --atime-preserve.
  21405. X
  21406. X    * Makefile, configure.in: Arrange to use local malloc on HP-UX.
  21407. X
  21408. X    * port.h Use the canonical Autoconf chunk for alloca instead
  21409. X    of just    looking for gcc.
  21410. X
  21411. XWed Sep  9 03:16:58 1992  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21412. X
  21413. X        * port.h: If compiling with gcc, use __builtin_alloca.
  21414. X
  21415. XTue Sep  8 16:13:41 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21416. X
  21417. X    * extract.c: Removed long name support from here.
  21418. X    * list.c (read_header): Understand and skip longname/longlink
  21419. X    headers here.  Names for current file are stored in new global
  21420. X    variables.  All source files except create.c changed to refer
  21421. X    to current_file_name and current_link_name instead of fields
  21422. X    directly from the current header.
  21423. X
  21424. XThu Sep  3 12:41:08 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21425. X
  21426. X    * create.c (write_long): New function.
  21427. X    (dump_file): When writing link records or symlink records, use
  21428. X    new write_long function instead of mangling when the link
  21429. X    target is too long.
  21430. X    (start_header): Use write_long instead of mangling for long
  21431. X    names. 
  21432. X    * extract.c (saverec): Recognize LF_LONGNAME and LF_LONGLINK.
  21433. X    (saverec): Throughout, use longname and longlink if they are set.
  21434. X
  21435. XWed Sep  2 14:41:13 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21436. X
  21437. X    * mangle.c: This is now deprecated; retain extract_mangle for
  21438. X    backward compatability.
  21439. X
  21440. X    * list.c (print_header): patch from Chris Arthur to prevent 
  21441. X    printing 0 when the gid or uid is null.
  21442. X
  21443. X    * list.c (decode_header): patch from Chris Arthur to use the
  21444. X    gid field when the gid is empty, and similarly for uid.
  21445. X
  21446. X    * extract.c: saved_dir_info, saved_dir_info_head: new type and
  21447. X    var.
  21448. X    (extract_archive): When extracting directories, now save info
  21449. X    in saved_dir_info_head.
  21450. X    (restore_saved_dir_info): New function.
  21451. X    * list.c (read_and): Call restore_saved_dir_info at the end of
  21452. X    the run.
  21453. X    This patch is from Chris Arthur (csa@pennies.sw.stratus.com).
  21454. X
  21455. XMon Aug 31 15:39:55 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21456. X
  21457. X    * create.c (create_archive): If there are no names specified,
  21458. X    write nothing on the archive instead of dumping ".".  
  21459. X
  21460. X    * buffer.c (open_archive): Useful error message.
  21461. X     * tar.c, tar.h: Recognize f_atime_preserve.
  21462. X    * create.c (dump_file): Implement f_atime_preserve.
  21463. X
  21464. X    * rmt.h (_remdev): Don't require /dev/ to be in remote archive
  21465. X    names; obey new force-local flag.
  21466. X    * tar.c, tar.h: Implement new force-local flag.
  21467. X
  21468. X    * tar.c (describe): same-owner and same-order were confused.
  21469. X
  21470. X    * create.c (dump_file): Check for toplevel had sense reversed.
  21471. X
  21472. X    * buffer.c (new_archive): Don't free old_name...when these
  21473. X    come from the command line, they aren't malloced, and it isn't
  21474. X    important to save this trivial amount of memory.
  21475. X
  21476. X    * tar.h: replace ar_file with ar_files, n_ar_files,
  21477. X    cur_ar_files.
  21478. X    * buffer.c (open_archive): multi-volume compressed archives
  21479. X    never worked; give an appropriate error.  Change open of
  21480. X    ar_file to open of ar_files[0].
  21481. X    (writeerror, readerror, flush_archive): use
  21482. X    ar_files[cur_ar_file] instead of ar_file.
  21483. X    (new_archive): Necessary changes to support ar_files.
  21484. X    * tar.c (options): handle multiple tape drive arguments.
  21485. X
  21486. XFri Aug 28 17:42:13 1992  Michael I Bushnell  (mib@wookumz.gnu.ai.mit.edu)
  21487. X
  21488. X    * list.c (decode_header), create.c (start_header), tar.h (TMAGIC): 
  21489. X    Undo djm's changes below; tar does not support the final
  21490. X    Posix.1 format; it's bad to make it look like it does.
  21491. X
  21492. XSun Jul 19 02:13:46 1992  David J. MacKenzie  (djm@nutrimat.gnu.ai.mit.edu)
  21493. X
  21494. X    * port.h: Try to prevent redefining major.
  21495. X    * port.c: HAVE_BZERO -> minix.  Fix a typo.
  21496. X
  21497. X    * list.c (decode_header): Recognize the final POSIX.1 magic as
  21498. X    well as the early draft magic for ustar.
  21499. X    * create.c (start_header): Create a final POSIX.1 magic string
  21500. X    instead of an early draft string for ustar.
  21501. X    * tar.h (TMAGIC): Remove the trailing blanks.
  21502. X
  21503. X    * rmt.c, rtapelib.c: Use POSIX and STDC headers if available.
  21504. X    * rmt.h: Declare the external functions defined in rtapelib.c.
  21505. X
  21506. XTue Jul 14 00:44:37 1992  David J. MacKenzie  (djm@apple-gunkies.gnu.ai.mit.edu)
  21507. X
  21508. X    * pathmax.h: New file.
  21509. X    * port.h: Include it.
  21510. X    * create.c (create_archive): Allocate PATH_MAX instead of
  21511. X    NAME_MAX for temporary buffer so we don't have to figure out
  21512. X    what NAME_MAX is (portably).
  21513. X
  21514. XFri Jul 10 08:30:42 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21515. X
  21516. X    * gnu.c (collect_and_sort_names): write_dir_file has no argument.
  21517. X
  21518. X    * level-0, level-1: Avoid silly Sun awk lossage.
  21519. X
  21520. XMon Jul  6 20:11:32 1992  David J. MacKenzie  (djm@nutrimat.gnu.ai.mit.edu)
  21521. X
  21522. X    * port.c (rename): If unlinking the source at the end fails,
  21523. X    unlink the destination instead to avoid leaving a mess.
  21524. X
  21525. XFri Jul  3 15:16:42 1992  David J. MacKenzie  (djm@nutrimat.gnu.ai.mit.edu)
  21526. X
  21527. X    * buffer.c, diffarch.c, update.c, rtapelib.c: Change NO_MTIO to
  21528. X    HAVE_SYS_MTIO_H.
  21529. X
  21530. X    * port.c, tar.h: Change FOO_MISSING to HAVE_FOO.
  21531. X
  21532. XTue Jun 23 23:39:02 1992  David J. MacKenzie  (djm@goldman.gnu.ai.mit.edu)
  21533. X
  21534. X    * rmt.c: Add #ifdefs to work on ISC.
  21535. X
  21536. XWed May 20 00:12:27 1992  David J. MacKenzie  (djm@churchy.gnu.ai.mit.edu)
  21537. X
  21538. X    * port.h: Define major, minor, makedev if the system doesn't.
  21539. X
  21540. XWed May 13 21:16:38 1992  Michael I Bushnell  (mib@apple-gunkies.gnu.ai.mit.edu)
  21541. X
  21542. X    * gnu.c (add_dir_name): Store legitimate value into
  21543. X    dir_contents when get_dir_contents returns NULL.
  21544. X
  21545. XThu May  7 23:44:35 1992  Michael I Bushnell  (mib@apple-gunkies.gnu.ai.mit.edu)
  21546. X
  21547. X    * gnu.c (add_dir_name): Check for return of NULL from get_dir_contents;
  21548. X    see djm's change of Fri Jul 26 01:12:58 1991.
  21549. X
  21550. XMon May  4 22:50:57 1992  David J. MacKenzie  (djm@churchy.gnu.ai.mit.edu)
  21551. X
  21552. X    * tar.h: Make comments for option names say -- instead of +.
  21553. X
  21554. XThu Apr 30 03:09:16 1992  Noah Friedman  (friedman@nutrimat.gnu.ai.mit.edu)
  21555. X
  21556. X        * level-1: Added `$' before VOLNO_FILE in definition of TAR_PART1.
  21557. X        Added line to remove $VOLNO_FILE from any previous dump before
  21558. X        starting. 
  21559. X          
  21560. X        * level-0, level-1: Change long options to use `--' instead of `+'
  21561. X        (support for `+' will go away soon) 
  21562. X
  21563. XWed Apr 29 14:23:10 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21564. X
  21565. X    * tar.c, tar.t: Added +volno-file option.
  21566. X    buffer.c: New functions init_volume_number,
  21567. X    closeout_volume_number.
  21568. X    tar.c (main): Call new functions in the right place.
  21569. X
  21570. X    * buffer.c (fl_write, fl_read): Mod to allow losing tape
  21571. X    drives which use short counts to indicate end of tape
  21572. X    correctly handle the multi-tape stuff.  The read half won't
  21573. X    co-exist with f_reblock; there's no way to fix that, of
  21574. X    course.
  21575. X
  21576. X    * tar.c, tar.h: Added new option +show-omitted-dirs, from
  21577. X    Karl Berry.  
  21578. X    list.c (read_and): Implemented show-omitted-dirs.
  21579. X
  21580. X    * tar.c, tar.h: Added new option +checkpoint.
  21581. X    buffer.c (fl_read, fl_write): Implemented +checkpoint lazily.
  21582. X
  21583. X    * create.c (dump_file): Added toplevel argument; some devices
  21584. X    can be negative, so the old method was bogus.  All callers
  21585. X    changed. 
  21586. X
  21587. X    * tar.c, tar.h: Added new option +ignore-failed-read.
  21588. X    create.c (dump_file): Implemented +ignore-failed-read.
  21589. X
  21590. X    * create.c (finish_sparse_file): Commented out debugging printf.
  21591. X
  21592. X    * tar.c, tar.h: Added new option +remove-files to delete files
  21593. X    after they are added to the archive.
  21594. X    create.c (dump_file): Implemented +remove-files for
  21595. X    everything but directories.  I don't think they need it.
  21596. X
  21597. XTue Apr 28 13:21:42 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21598. X
  21599. X    * create.c: (dump_file): save_name needs to be set equal to p,
  21600. X    not something inside the header, because the header changes at
  21601. X    the first buffer flush.
  21602. X
  21603. XFri Apr 24 10:41:13 1992  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21604. X
  21605. X    * create.c: Djm incorrectly moved the include of port.h to
  21606. X    precede the include of sys/file.h; restored.
  21607. X
  21608. X    * tar.c (main): Cases CMD_EXTRACT and CMD_LIST: declare error
  21609. X    string with const.
  21610. X
  21611. X    * gnu.c (collect_and_sort_names): Leave if around
  21612. X    write_dir_file in place.
  21613. X
  21614. XWed Apr 22 02:16:14 1992  David J. MacKenzie  (djm@churchy.gnu.ai.mit.edu)
  21615. X
  21616. X    * rtapelib.c: SIGTYPE -> RETSIGTYPE.
  21617. X
  21618. XMon Mar  9 22:42:05 1992  David J. MacKenzie  (djm@nutrimat.gnu.ai.mit.edu)
  21619. X
  21620. X    * rtapelib.c: Reformat and make comments more complete.
  21621. X    Rename a few variables for clarity.
  21622. X
  21623. XThu Mar  5 14:07:34 1992  David J. MacKenzie  (djm@nutrimat.gnu.ai.mit.edu)
  21624. X
  21625. X    * tar.c (describe): Document long options as starting with --.
  21626. X
  21627. XThu Jan 23 22:54:41 1992  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21628. X
  21629. X    * tar.c (options): Check get_date return value for error indication.
  21630. X
  21631. XTue Dec 24 00:03:03 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21632. X
  21633. X    * tar.c, gnu.c, extract.c, create.c, port.h, rmt.h: Change
  21634. X    POSIX ifdefs to HAVE_UNISTD_H and _POSIX_VERSION.
  21635. X
  21636. XFri Dec 20 13:50:38 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21637. X
  21638. X    * testpad.c (main): flush stderr so perror and fprintf
  21639. X    cooperate right.
  21640. X
  21641. XWed Dec 18 16:52:42 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21642. X
  21643. X    * port.h: Check MAJOR_IN_MKDEV and MAJOR_IN_SYSMACROS to find
  21644. X    where to get major, minor and makedev.
  21645. X    * create.c, list.c, update.c: Don't check USG to include
  21646. X    sys/sysmacros.h.
  21647. X
  21648. XThu Dec 12 21:57:10 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21649. X
  21650. X    * mangle.c (extract_mangle): Correctly null terminate name of
  21651. X    link target.
  21652. X
  21653. XThu Nov 21 07:44:18 1991  Michael I Bushnell  (mib at nutrimat)
  21654. X
  21655. X    * create.c (dump_file, at start of ISREG output loop): use
  21656. X    filename from header instead of real name to make sure that we
  21657. X    get the mangled version and not one that is too long and
  21658. X    overflows buffers.
  21659. X
  21660. XSat Nov 16 01:37:45 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21661. X
  21662. X    * tar.h: Use new criteria for STDC version of msg.
  21663. X
  21664. XSat Nov  2 21:31:57 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21665. X
  21666. X    * create.c, gnu.c, tar.c: Use DIRENT instead of NDIR to select
  21667. X    between dirent.h and ndir.h for USG.
  21668. X
  21669. X    * port.c: Rename WANT_FOO to FOO_MISSING to make sharing code
  21670. X    and configure script with other utilities easier.  Use
  21671. X    VPRINTF_MISSING and DOPRNT_MISSING instead of FOO_MSG to
  21672. X    select error reporting routines.
  21673. X
  21674. XThu Oct 17 20:19:02 1991  Michael I Bushnell  (mib at churchy.gnu.ai.mit.edu)
  21675. X
  21676. X    * level-0: Repair damage from previous mod: stdin to rsh must
  21677. X    be the terminal or tar's questions lose.
  21678. X
  21679. XSat Aug 31 15:05:27 1991  Noah Friedman  (friedman at nutrimat.gnu.ai.mit.edu)
  21680. X
  21681. X        * level-0: Fixed several syntax errors associated with
  21682. X          stdout/stderr redirection.
  21683. X          Made sure remote host executes commands from sh where redirection
  21684. X          is necessary, since root's shell might be csh in some places and
  21685. X          the redirect syntax differs.
  21686. X
  21687. XThu Aug 29 00:54:01 1991  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21688. X
  21689. X    * tar.c (long_options).  Fixed info-script long option.
  21690. X
  21691. XMon Aug 26 16:53:50 1991  David J. MacKenzie  (djm at pogo.gnu.ai.mit.edu)
  21692. X
  21693. X    * configure, Makefile.in: Only put $< in Makefiles if VPATH
  21694. X    is being used, because older makes don't understand it.
  21695. X
  21696. XMon Aug 19 01:47:57 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21697. X
  21698. X    * create.c: Indent '#pragma alloca' so non-ANSI compilers
  21699. X    don't choke on it.
  21700. X
  21701. XWed Aug 14 14:10:43 1991  David J. MacKenzie  (djm at geech.gnu.ai.mit.edu)
  21702. X
  21703. X    * list.c (UGSWIDTH): Increase from 11 (sort of like Unix tar) to
  21704. X    18, so that with normal user and group names of <= 8 chars,
  21705. X    the columns never shift in a tar -t listing.
  21706. X
  21707. XFri Aug  2 00:41:08 1991  David J. MacKenzie  (djm at apple-gunkies)
  21708. X
  21709. X    * Makefile.in (dist): Include texinfo.tex and tar.info*.
  21710. X    (install): Install tar.info*.
  21711. X    * configure: Set INSTALLDATA.
  21712. X
  21713. X    * configure: Create config.status.  Remove it and Makefile if
  21714. X    interrupted while creating them.
  21715. X
  21716. X    * configure: Check for +srcdir etc. arg and look for
  21717. X    Makefile.in in that directory.  Set VPATH if srcdir is not `.'.
  21718. X    * Makefile.in: Add `prefix'.
  21719. X    (tar.info): New target.
  21720. X
  21721. XTue Jul 30 17:08:04 1991  David J. MacKenzie  (djm at apple-gunkies)
  21722. X
  21723. X    * configure: NEED_TZSET has become FTIME_MISSING.
  21724. X
  21725. XMon Jul 29 19:23:10 1991  David J. MacKenzie  (djm at wombat.gnu.ai.mit.edu)
  21726. X
  21727. X    * port.c [F_CHSIZE]: Additional version.
  21728. X
  21729. XSat Jul 27 22:27:47 1991  David J. MacKenzie  (djm at wombat.gnu.ai.mit.edu)
  21730. X
  21731. X    * rmt.h: Clean up ifdefs.
  21732. X
  21733. X    * makefile.pc: Fix typo.
  21734. X    port.h: Change MSDOS to __MSDOS__.
  21735. X    [__MSDOS__]: Define off_t.  Include io.h and not sys/param.h.
  21736. X    [__TURBOC__]: Use void * and don't define const.
  21737. X
  21738. XFri Jul 26 01:12:58 1991  David J. MacKenzie  (djm at bleen)
  21739. X
  21740. X    * buffer.c: Rename `eof' to `hit_eof' to avoid conflict with an
  21741. X    MSDOS function.
  21742. X    * gnu.c (get_dir_contents): Return NULL, not "\0\0\0\0", on error.
  21743. X    * diffarch.c (diff_archive): Open files in binary mode.
  21744. X    Don't use or free a non-malloc'd return value from get_dir_contents.
  21745. X    * msd_dir.c [__TURBOC__]: Include stdlib.h.
  21746. X    * rmt.h: lseek returns off_t, not long.
  21747. X
  21748. X    * tar.c (describe): -X is +exclude-from, not +exclude.
  21749. X    (names_notfound): Free memory only if amiga, not !unix.
  21750. X
  21751. X    * tar.h, tar.c: Add +null option to make -T read
  21752. X    null-terminated filenames (such as those produced by GNU find
  21753. X    -print0), and disable -C option.
  21754. X    This guarantees that odd filenames will get archived.
  21755. X    * tar.c (read_name_from_file): New function.
  21756. X    (name_next): Call it instead of fgets.
  21757. X
  21758. XWed Jul 24 11:17:48 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21759. X
  21760. X    * create.c [_AIX]: Declare alloca.
  21761. X
  21762. X    * buffer.c (open_archive): Check for successful open before,
  21763. X    not after, fstatting the fd.
  21764. X
  21765. XTue Jul 23 20:51:31 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21766. X
  21767. X    * configure: Only define BSD42 if sys/file.h exists.
  21768. X    If alloca is missing and /usr/ucblib exists (SVR4), use it
  21769. X    instead of -lPW.
  21770. X
  21771. X    * port.h [!__STDC__]: #define const.
  21772. X    * gnu.c (dirent_cmp): Fix args to agree with ANSI C prototype.
  21773. X    * create.c: Declare ck_realloc.
  21774. X    * gnu.c, diffarch.c: Move check for symlinks to after port.h include.
  21775. X
  21776. XSat Jul 20 00:03:54 1991  David J. MacKenzie  (djm at apple-gunkies)
  21777. X
  21778. X    * msd_dir.[ch]: Use POSIX-style `struct dirent' instead of
  21779. X    `struct direct'.
  21780. X    * create.c, gnu.c, tar.c: Adjust callers.
  21781. X
  21782. XThu Jul 18 00:05:01 1991  David J. MacKenzie  (djm at bleen)
  21783. X
  21784. X    * port.c (ck_malloc, ck_realloc): Return PTR, not char *.
  21785. X    * gnu.c, create.c, tar.c: Fix decls.
  21786. X
  21787. X    * port.c: Don't use the preprocessor to guess missing
  21788. X    functions on Unix; let configure do it.
  21789. X    [WANT_GETWD] (getwd): Function removed; not needed because
  21790. X    getcwd is used if needed.
  21791. X    * gnu.c, tar.c: Use getcwd if POSIX.
  21792. X
  21793. X    * rtapelib.c: Use SIGTYPE instead of testing SIGNAL_VOID.
  21794. X    Default to void (more common these days) instead of int.
  21795. X
  21796. X    * tar.c, gnu.c, mangle.c: Remove VOIDSTAR defn.  Use PTR instead.
  21797. X    * port.h: Define PTR.
  21798. X
  21799. X    * gnu.c, tar.c [__MSDOS__ || USG]: Remove incorrect getcwd
  21800. X    decl; put correct one in port.h [!POSIX].
  21801. X
  21802. X    * tar.c (describe): Print on stdout instead of stderr; it's
  21803. X    not so much a usage message (since you have to ask for it
  21804. X    explicitly) as on-line help, and you really need to be able to
  21805. X    page it because it's more than a screen long.
  21806. X
  21807. X    * Make #ifdefs for sys/file.h or fcntl.h, directory header,
  21808. X    sys/mtio.h consistent between files.  Use NO_MTIO instead of
  21809. X    tricks with USG and HAVE_MTIO and NO_RMTIOCTL.
  21810. X    * Move decls of ANSI C and POSIX functions to port.h and
  21811. X    use standard headers to declare them if available
  21812. X    [STDC_HEADERS or POSIX].
  21813. X    * Add many missing function declarations and return types.
  21814. X    * Some places used __MSDOS__, some MSDOS; standardize on __MSDOS__.
  21815. X    * Change S_IF macros to S_IS for POSIX.
  21816. X    * port.h: Define appropriate S_IS macros if missing.
  21817. X    * port.h: Rename macros for testing exit status to conform to
  21818. X    POSIX; use the system's versions if available [POSIX].
  21819. X    * Use POSIX PATH_MAX and NAME_MAX instead of MAXPATHLEN and MAXNAMLEN.
  21820. X    * port.h: Define PATH_MAX and NAME_MAX.
  21821. X    * create.c, gnu.c, tar.c: Use ck_malloc and free instead of
  21822. X    auto arrays of size PATH_MAX or NAME_MAX, since with pathconf
  21823. X    they might not be constants.
  21824. X    * Move all definitions of O_* to port.h to reduce redundancy.
  21825. X    * Make all source files that now need to include port.h do so.
  21826. X    * port.c: Remove #undefs of WANT_* so you can use -DWANT_*
  21827. X    when compiling, instead of having to edit port.c.
  21828. X    [WANT_DUMB_GET_DATE] (get_date): Function removed.
  21829. X    Even systems without bison can get bison output and compile it.
  21830. X    [WANT_STRING] (index, rindex, bcopy, bzero, bcmp): Functions
  21831. X    removed; the translation is now done by macros in port.h.
  21832. X    * wildmat.c (wildmat): Use POSIX.2 '!' instead of '^' to negate
  21833. X    character classes.
  21834. X
  21835. XMon Jul 15 13:47:45 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21836. X
  21837. X    * testpad.c (main): Return type void.
  21838. X
  21839. X    * port.c [WANT_STRING]: Don't include memory.h if NO_MEMORY_H.
  21840. X
  21841. X    * create.c (dump_file) [AIX]: Fix typo, `allocate' for `alloca'.
  21842. X    * gnu.c (collect_and_sort_names): Move misplaced brace out of #ifdef.
  21843. X    From: Minh Tran-Le <TRANLE@intellicorp.com>.
  21844. X
  21845. X    * configure: Also look in sys/signal.h for signal decl.
  21846. X
  21847. XWed Jul 10 01:42:55 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21848. X
  21849. X    * Rename rtape_server.c to rmt.c and rtape_lib.c to rtapelib.c.
  21850. X
  21851. X    * configure, Makefile.in: $(INSTALLPROG) -> $(INSTALL).
  21852. X
  21853. XTue Jul  9 01:38:37 1991  David J. MacKenzie  (djm at wookumz.gnu.ai.mit.edu)
  21854. X
  21855. X    * Most files: Refer to GPL version 2.
  21856. X    * COPYING: Use version 2.
  21857. X
  21858. X    * port.c [__TURBOC__] (utime): New function.
  21859. X
  21860. X    * xmalloc: New function (just calls ck_malloc), for alloca.c
  21861. X    and bison.simple (in getdate.y output).
  21862. X
  21863. X    * Makefile.in (AUX): Include alloca.c and tcexparg.c, a
  21864. X    command line globber for Turbo C.
  21865. X
  21866. XMon Jul  8 14:30:52 1991  David J. MacKenzie  (djm at geech.gnu.ai.mit.edu)
  21867. X
  21868. X    * testpad.c: Open and write to testpad.h instead of stdout,
  21869. X    because some MS-DOS makes (Borland's at least) can't do
  21870. X    redirection in commands.
  21871. X    * Makefile.in: Don't redirect testpad output.
  21872. X
  21873. XMon Jul  8 12:56:35 1991  Michael I Bushnell  (mib at churchy.gnu.ai.mit.edu)
  21874. X
  21875. X    * buffer.c (fl_read): Missing \n in printf.
  21876. X
  21877. XMon Jul  8 03:40:28 1991  David J. MacKenzie  (djm at geech.gnu.ai.mit.edu)
  21878. X
  21879. X    * create.c, extract.c, gnu.c, diffarch.c, tar.c: Comment out
  21880. X    unused variables. 
  21881. X
  21882. X    * tar.c (options): Cast get_date arg to VOIDSTAR instead of
  21883. X    `struct timeb *', since on some non-BSD systems the latter is
  21884. X    undefined.
  21885. X
  21886. XSat Jul  6 04:53:14 1991  David J. MacKenzie  (djm at geech.gnu.ai.mit.edu)
  21887. X
  21888. X    * Replace Makefile with configure, Makefile.in, and makefile.pc.
  21889. X    Update README with current compilation instructions.
  21890. X
  21891. X    * port.c [WANT_RENAME] (rename): New function.
  21892. X
  21893. XWed Jul  3 18:10:52 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21894. X
  21895. X    * testpad.c (main): Avoid warning from some compilers on array
  21896. X    address. 
  21897. X
  21898. X    * rtape_server.c (sys_errlist): Should be declared extern.
  21899. X
  21900. XMon Jul  1 14:14:06 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21901. X
  21902. X    * Release of version 1.10; appropriate changes to README.
  21903. X
  21904. X    * create.c: Removed printf's about sparse files.
  21905. X
  21906. X    * Fix a misplaced quote in level-0 and change some >& into
  21907. X    2>&1.
  21908. X
  21909. XFri Jun 21 23:04:31 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21910. X
  21911. X    * list.c (skip_extended_headers): Userec was being called in
  21912. X    the wrong place.
  21913. X
  21914. XThu Jun 20 19:10:35 1991  David J. MacKenzie  (djm at geech.gnu.ai.mit.edu)
  21915. X
  21916. X    * tar.h: Use ANSI prototypes for msg and msg_perror if
  21917. X    STDC_MSG is defined, even if BSD42 is also.
  21918. X
  21919. X    * Makefile: Replace DESTDIR with bindir.
  21920. X    (install): Don't install tar.texinfo.  There's no standard
  21921. X    place for texinfo files, and /usr/local/man is inappropriate.
  21922. X    Add TAGS, distclean, and realclean targets and SHELL= line.
  21923. X
  21924. X    * version.c: Move old change history to bottom of ChangeLog.
  21925. X
  21926. XWed Jun 12 12:43:58 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21927. X
  21928. X    * rtape_lib.c (__rmt_write): #ifdef should reference
  21929. X    SIGNAL_VOID, not USG.
  21930. X
  21931. XWed Jun  5 14:57:11 1991  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21932. X
  21933. X    * tar.c (name_match, addname): Ugly hack to handle -C without
  21934. X    any files specified.  
  21935. X    tar.h (struct name): New field for ugly hack.
  21936. X
  21937. XMon Jun  3 14:46:46 1991  Michael I Bushnell  (mib@geech.gnu.ai.mit.edu)
  21938. X
  21939. X    * testpad.c: New file to determine if we need special padding
  21940. X    in struct header in tar.h.
  21941. X
  21942. X    * tar.h (struct header): include padding if necessary, include
  21943. X    testpad.h.
  21944. X
  21945. X    * Makefile: rules to create testpad.h, etc.
  21946. X
  21947. XWed May 22 16:02:35 1991  Michael I Bushnell  (mib@churchy.gnu.ai.mit.edu)
  21948. X
  21949. X    * tar.c (options): -L takes an argument.
  21950. X
  21951. X    * rtape_lib.c (__rmt_open): add /usr/bin/nsh to the list of
  21952. X    remote shell programs.
  21953. X
  21954. X    * create.c: define MAXPATHLEN if we don't get it from a system
  21955. X    header file.
  21956. X
  21957. X    * create.c (deal_with_sparse): return a real return value if
  21958. X    we can't open the file.
  21959. X
  21960. X    * tar.c (long_options): +newer takes an argument.
  21961. X    (describe): fix printing in various trivial ways
  21962. X
  21963. XTue May 21 17:15:19 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21964. X
  21965. X    * tar.c (long_options): +get and +concatentate don't require arguments
  21966. X
  21967. XMon May 20 15:55:30 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21968. X
  21969. X    * create.c (write_eot): Don't try and write an EOF if we are
  21970. X    already at one.
  21971. X
  21972. X    * port.c (strstr): Looking for null string should return zero.
  21973. X
  21974. XSun May 19 22:30:10 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  21975. X
  21976. X    * tar.c (options): -l doesn't take an argument
  21977. X
  21978. X    * Makefile: minor fix for SGI 4D defines from torda@scum.ethz.ch
  21979. X
  21980. X    * rtape_server.c (main.c): Suggested mod for 386/AIX from
  21981. X    Minh Tran-Le.  I'm suspicious about this one.
  21982. X
  21983. X    * create.c (dump_file): Mods from Minh Tran-Le for hidden
  21984. X    files on AIX.
  21985. X    gnu.c (collect_and_sort_name, get_dir_contents): AIX hidden file mod.
  21986. X
  21987. X    * tar.c: (name_next): Mod from David Taylor to allow -C inside
  21988. X    a file list given to -T.
  21989. X
  21990. X    * Makefile: Comment describing presence of USE_REXEC.
  21991. X
  21992. X    * extract.c (extract_archive, case LF_SPARSE): zero check for
  21993. X    last element on numbytes needs to look at value after
  21994. X    converted from octal.
  21995. X
  21996. X    * port.c: Don't always demand strstr, check for HAVE_STRSTR
  21997. X    instead.
  21998. X    Makefile: Comment describing presence of HAVE_STRSTR option.
  21999. X
  22000. XSun May 19 18:39:48 1991  David J. MacKenzie  (djm at churchy.gnu.ai.mit.edu)
  22001. X
  22002. X    * port.c (get_date): Renamed from getdate, to avoid SVR4 conflict.
  22003. X    * tar.c: Call get_date instead of getdate.
  22004. X
  22005. XFri May 10 02:58:17 1991  Noah Friedman  (friedman at nutrimat)
  22006. X
  22007. X        * tar.c:  added "\n\" to the end of some documentation strings
  22008. X          where they were left off.  
  22009. X
  22010. XThu May  9 17:28:54 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  22011. X
  22012. X    * Makefile: added level-0, level-1, and backup-specs to AUX.
  22013. X    * version.c: changed to 1.10 beta.
  22014. X    * README: updated for 1.10 beta release.
  22015. X
  22016. XTue Apr  2 12:04:54 1991  Michael I Bushnell  (mib at godwin)
  22017. X
  22018. X    * create.c (dump_file): HPUX's st_blocks is in 1024 byte units
  22019. X    instead of 512 like the rest of the world, so I special cased
  22020. X    it.
  22021. X    * tar.c: Undo Noah's changes.
  22022. X
  22023. XMon Apr  1 17:49:28 1991  Noah Friedman  (friedman at wookumz.gnu.ai.mit.edu)
  22024. X
  22025. X        (This ought to be temporary until things are fixed properly. )
  22026. X
  22027. X        * tar.c: (struct option long_options):  flag for "sparse" zero if
  22028. X          compiling under hpux. 
  22029. X          tar.c: (functon options): case 'S' is a no-op if compiling under
  22030. X          hpux. 
  22031. X
  22032. XSat Mar 30 12:20:41 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  22033. X
  22034. X    * tar.h: new variable tape_length.
  22035. X
  22036. X    * tar.c (options): add new option +tape-length / -L.
  22037. X
  22038. X    * buffer.c (fl_write): Turn #ifdef TEST code for limited tape
  22039. X    length on always, for tape-length option.
  22040. X
  22041. X    * create.c (dump_file): avoid apollo lossage where S_IFIFO == S_IFSOCK.
  22042. X
  22043. X        * buffer.c: include regex.h
  22044. X    * buffer.c (fl_read, open_archive): Use regex routines for
  22045. X    volume header match.
  22046. X    * xmalloc.c: removed file; wasn't necessary.
  22047. X    * tar.c: (main) use ck_malloc instead of xmalloc.
  22048. X
  22049. XThu Mar 28 04:05:05 1991  Noah Friedman  (friedman at goldman)
  22050. X
  22051. X        * regex.c, regex.o: New links. 
  22052. X        * tar.c: include regex.h. 
  22053. X        * Makefile (OBJ2): Add regex.o.
  22054. X        (regex.o, tar.o): Depend on regex.h
  22055. X        (SRC2, AUX): Add the new files.
  22056. X
  22057. XSat Mar 23 15:39:42 1991  Noah Friedman  (friedman at wookumz.gnu.ai.mit.edu)
  22058. X
  22059. X        * Makefile: added default flags and options for compiling under
  22060. X          hpux.
  22061. X
  22062. X        * Added files alloca.c and xmalloc.c 
  22063. X
  22064. XSat Mar 23 14:35:31 1991  Michael I Bushnell  (mib at geech.gnu.ai.mit.edu)
  22065. X
  22066. X    * port.c: Define WANT_VALLOC in HPUX.
  22067. X
  22068. XFri Mar 15 06:20:15 1991  David J. MacKenzie  (djm at geech.ai.mit.edu)
  22069. X
  22070. X    * rtape_lib.c: If USG and not HAVE_MTIO, define NO_RMTIOCTL
  22071. X    automatically.
  22072. X    (_rmt_rexec): Temporarily re-open stdin and stdout to
  22073. X    /dev/tty, to guarantee that rexec() can prompt and read the
  22074. X    login name and password from the user.
  22075. X    From pascal@cnam.cnam.fr (Pascal Meheut).
  22076. X    * Makefile: Mention -DUSE_REXEC.
  22077. X
  22078. XFri Mar  8 20:15:11 1991  Michael I Bushnell  (mib at wookumz.ai.mit.edu)
  22079. X
  22080. X    * tar.h, Makefile:  Makefile CPP macro HAVE_SIZE_T might be
  22081. X    useful for some people.
  22082. X
  22083. X    * gnu.c: lstat->stat define where appropriate
  22084. X
  22085. X    * buffer.c (fl_write): keep track of amount written for +totals.
  22086. X    * tar.c, tar.h: set flag f_totals from +totals option
  22087. X    * tar.h (f_totals, tot_written): new variables
  22088. X    * tar.c (main): print total written with CMD_CREATE
  22089. X
  22090. X    * tar.c (main): return appropriate exit status
  22091. X
  22092. XThu Jan 17 00:50:21 1991  David J. MacKenzie  (djm at apple-gunkies)
  22093. X
  22094. X    * port.c: Remove a spurious `+' between functions (a remnant
  22095. X    of a context diff, apparently).
  22096. X
  22097. XWed Jan  9 19:43:59 1991  Michael I Bushnell  (mib at pogo.ai.mit.edu)
  22098. X
  22099. X    * create.c (where_is_data): Rewritten to be better, and then
  22100. X    #ifdef-ed out.
  22101. X    (deal_with_sparse): Severly pruned.  Now we write or don't
  22102. X    write only complete blocks, not worrying about partial blocks.
  22103. X    This simplifies calculations, removes bugs, and elides the
  22104. X    second scan through the block.  The first was zero_record, the
  22105. X    second was where_is_data.
  22106. X
  22107. XMon Jan  7 17:13:29 1991  Michael I Bushnell  (mib at wookumz.ai.mit.edu)
  22108. X
  22109. X    * create.c (deal_with_sparse): Second computation (for short
  22110. X    reads) of numbytes increment had subtraction backwards.
  22111. X    Need to handle calling where_is_data better when we did a
  22112. X    short read (it might go past the end of the read), also, set
  22113. X    sparsearray[...].offset in this case too.
  22114. X
  22115. XFri Jan  4 12:24:38 EST 1991    Jay Fenlason (hack@ai.mit.edu)
  22116. X
  22117. X    * buffer.c  Return a special error code if the archive you're
  22118. X    trying to read starts with a different label than the one specified
  22119. X    on the command line.
  22120. X
  22121. XWed Jan  2 12:05:21 EST 1991    Jay Fenlason (hack@ai.mit.edu)
  22122. X
  22123. X    * gnu.c  Prepend the current directory to the gnu_dumpfile, so that
  22124. X    -C's won't affect where the output goes. (sigh.)
  22125. X
  22126. XTue Dec 18 18:05:59 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22127. X
  22128. X    * (gnu.c)  Don't complain if the gnudumpfile we're reading info
  22129. X    from doesn't exist.
  22130. X
  22131. X    * create.c  Write out gnudumpfile after finishing writing the archive.
  22132. X
  22133. X    * tar.c  Add +exclude FNAME, and make +exclude-from do what +exclude
  22134. X    used to.
  22135. X
  22136. X        Make +version an operation, not an option.
  22137. X
  22138. X        add +confirmation alias for +interactive.
  22139. X
  22140. XTue Dec  4 13:28:08 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22141. X
  22142. X    * tar.c (check_exclude)  Don't let MUMBLE match MUMBLE.c or fooMUMBLE
  22143. X    but only foo/MUMBLE
  22144. X
  22145. X    * Add the name mangler (mangle.c, plus changes to create.c and
  22146. X    extract.c)
  22147. X
  22148. X    * extract.c  Three small patches from Chip Salzenberg
  22149. X    (tct!chip@uunet.uu.net)
  22150. X
  22151. X        Don't complain when extracting a link, IFF it already exists.
  22152. X
  22153. X        Don't complain when extracting a directory IFF it already
  22154. X        exists.
  22155. X
  22156. X        Don't ad u+wx to directories when running as root.
  22157. X
  22158. X    * gnu.c  Some changes from Chip Salzenberg to make
  22159. X    +listed-incremental work.
  22160. X
  22161. X    * port.c Add the F_FREESP emulation of the ftruncate syscall.
  22162. X
  22163. XWed Nov 21 15:57:07 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22164. X
  22165. X    Remove excess \n from lots of msg() calls.
  22166. X
  22167. XMon Nov 19 14:09:43 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22168. X
  22169. X    * tar.c  Rename +volume to +label
  22170. X
  22171. XFri Nov 16 15:43:44 1990  David J. MacKenzie  (djm at apple-gunkies)
  22172. X
  22173. X    * tar.c (describe): Include the default values for -b and -f
  22174. X    (as set in the Makefile) in the message.
  22175. X
  22176. XThu Nov 15 13:36:45 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22177. X
  22178. X    * extract.c (extract_archive)  Do the utime() call before the
  22179. X    chmod() call, 'cuz some versons of utime() trash the file's mode
  22180. X    bits.
  22181. X
  22182. X    * list.c (read_and)    Call do_something on volume headers and
  22183. X    multivol files even if they don't match the names we're looking for,
  22184. X    etc. . .
  22185. X
  22186. XTue Nov  6 13:51:46 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22187. X
  22188. X    * port.c (un-quote-string)    Don't try to write a null
  22189. X    if there's already one there.
  22190. X
  22191. XThu Nov  1 14:58:57 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22192. X
  22193. X    * buffer.c  (new_volume) fflush(msg_file) before reading for
  22194. X    confirmation on new volume.  On EOF or error, print error msg and
  22195. X    abort.
  22196. X
  22197. XMon Oct 29 12:06:35 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22198. X
  22199. X    * getdate.y    Use new version of getdate().
  22200. X
  22201. X    * tar.c (name_add) Use sizeof(char *) instead of sizeof(int)
  22202. X
  22203. X    * README give the correct return address.
  22204. X
  22205. XThu Oct 25 16:03:58 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22206. X
  22207. X    rtape_lib.c    Change RMTIOCTL to NO_RMTIOCTL, so it is on by default.
  22208. X
  22209. X    rmt.h        Add _isrmt() #define for NO_REMOTE case.
  22210. X
  22211. X    gnu.c        Add forward reference for add_dir_name().
  22212. X
  22213. XTue Oct 16 11:04:52 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22214. X
  22215. X    1.09    New -G file implementation of gnu-dump stuff.
  22216. X
  22217. X    * tar.c  (name_add)  Get the calls to ck_realloc and ck_malloc right.
  22218. X
  22219. XThu Oct 11 11:23:38 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22220. X
  22221. X    * gnu.c  Fix A couple of typos.
  22222. X
  22223. XWed Sep 19 13:35:03 1990  David J. MacKenzie  (djm at apple-gunkies)
  22224. X
  22225. X    * getdate.y [USG] (ftime): Use `daylight' unless
  22226. X    DAYLIGHT_MISSING is defined.
  22227. X
  22228. XMon Sep 17 18:04:21 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22229. X
  22230. X    * gnu.c (gnu_restore)  Don't use a passed char* for the
  22231. X    file name, use skipcrud+head->header.name, just like everything
  22232. X    else does.  This means that gnu_restore will still work with
  22233. X    small buffers, etc.
  22234. X
  22235. XThu Sep 13 15:01:17 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22236. X
  22237. X    * tar.c (add_exclude)  Don't bus-error if the exclude file doesn't
  22238. X    end with a newline.
  22239. X
  22240. XSun Sep  9 22:35:27 1990  David J. MacKenzie  (djm at albert.ai.mit.edu)
  22241. X
  22242. X    * Makefile (dist): Remove .fname when done.
  22243. X
  22244. XThu Sep  6 12:48:58 EDT 1990    Jay Fenlason (hack@ai.mti.edu)
  22245. X
  22246. X    * gnu.c (gnu_restore) Rember to skip_file() over the directory
  22247. X    contents, even if we don't have to do anything with them.
  22248. X
  22249. X    * create.c extract.c diffarch.c  Free sparsearray after we're done
  22250. X    with it.
  22251. X
  22252. XTue Sep  4 10:18:50 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22253. X
  22254. X    * Makefile  Include gnu.c in dist
  22255. X
  22256. X    * gnu.c move add_dir above read_dir_file so that cc doesn't complain
  22257. X    about add_dir returning void.
  22258. X
  22259. XSun Sep  2 20:46:34 1990  David J. MacKenzie  (djm at apple-gunkies)
  22260. X
  22261. X    * getdate.y: Declare some more functions and add storage
  22262. X    classes where omitted to shut compiler up.
  22263. X    [USG] (ftime): Don't use extern var `daylight'; appears that
  22264. X    some systems don't have it.
  22265. X
  22266. XWed Aug 29 00:05:06 1990  David J. MacKenzie  (djm at apple-gunkies)
  22267. X
  22268. X    * getdate.y (lookup): In the code that allows `Aug.' to be
  22269. X    recognized as `Aug', don't chop off the final `.' from words
  22270. X    like `a.m.', so they can be recognized.
  22271. X
  22272. XThu Aug 16 11:34:07 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22273. X
  22274. X    * buffer.c (open_archive)  If -O, write verbosity to stderr
  22275. X    instead of stdout.
  22276. X
  22277. XFri Aug 10 12:29:28 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22278. X
  22279. X    * getdate.y  Handle an explicit DST in the input string.
  22280. X    A dozen line patch from Per Foreby (perf@efd.lth.se).
  22281. X
  22282. XMon Jul 16 13:05:11 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22283. X
  22284. X    * tar.c  rename -g -G +incremental, +listed-imcremental, etc.
  22285. X
  22286. XFri Jul 13 14:10:33 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22287. X
  22288. X    * tar.c  Make +newer and +newer-mtime work according to their names.
  22289. X
  22290. X    * gnu.c  If +newer or +newer-mtime, use the time specified on the
  22291. X    command line.
  22292. X
  22293. X    * buffer.c, create.c  Add test to see if dimwit is trying to
  22294. X    archive the archive.
  22295. X
  22296. X    * tar.c  (long_options[]) re-ordered, so that groups of similar
  22297. X    options are next to each other. . .  I think.
  22298. X
  22299. X        (describe)  Modified to more closely reflect reality.
  22300. X
  22301. XFri Jul  6 13:13:59 EDT 1990    Jay Fenlason (hack@ai.mit.edu)
  22302. X
  22303. X    * tar.c  add compile-time option for SYS V (?) style
  22304. X    tape-drive names /dev/rmt/{n}[lmh]
  22305. X
  22306. X    * tar.c  Fix getopt-style stuff so that -C always works correctly.
  22307. X
  22308. X    * gnu.c, tar.c make filename to -G optional.
  22309. X
  22310. X    * {all over}, replace some fprintf(stderr...) calls with calls
  22311. X    to msg().
  22312. X
  22313. X    * port.c  Make -Dmumble_MSG option on command line override
  22314. X    internal assumptions.
  22315. X
  22316. X    * Makefile  Mention -Dmumble_MSG options
  22317. X
  22318. XFri Jul  6 02:35:31 1990  David J. MacKenzie  (djm at apple-gunkies)
  22319. X
  22320. X    * tar.c (options): Don't change `c' if it is 0, as getopt now
  22321. X    handles that internally.
  22322. X
  22323. XMon Jul  2 15:21:13 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22324. X
  22325. X    * gnu.c  (new file)  Moved all the f_gnudump stuff here where we
  22326. X    can keep track of it easier.  Also made -G take a file name where it
  22327. X    stores the inode information about directories so that we can
  22328. X    detect moved directores.
  22329. X
  22330. X    * create.c (dump_file)  Changed slightly to work with the new
  22331. X    f_gnudump.
  22332. X
  22333. X    * tar.c  Moved the f_gnudump stuff to gnu.c
  22334. X
  22335. X    * tar.c, extract.c  added the +do-chown option, which forces tar
  22336. X    to always try to chown the created files to their original owners.
  22337. X
  22338. X    * version.c  New version 1.09
  22339. X
  22340. XSun Jun 24 14:26:28 1990  David J. MacKenzie  (djm at albert.ai.mit.edu)
  22341. X
  22342. X    * create.c: Change ifdefs for directory library header
  22343. X    selection to be like the ones in tar.c.
  22344. X    * Makefile [Xenix]: Link with -ldir to get the dirent.h
  22345. X    directory library.
  22346. X
  22347. XThu Jun  7 03:31:51 1990  David J. MacKenzie  (djm at albert.ai.mit.edu)
  22348. X
  22349. X    * Makefile, buffer.c, diffarch.c: Change MTIO symbol to HAVE_MTIO
  22350. X    because SCO Xenix defines 'MTIO' for an incompatible tape driver
  22351. X    system in a file included by termio.h.
  22352. X    * tar.h: Don't define size_t for Xenix.
  22353. X
  22354. XTue Jun  5 11:38:00 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22355. X
  22356. X    * create.c (dump_file)  Only print the
  22357. X    "... is on a different filesystem..." if f_verbose is on.
  22358. X    also add a case for S_IFSOCK and treat it like a FIFO.
  22359. X    (Not sure if that's the right thing to do or not, but it's better
  22360. X    than all those Unknown File Type msgs.)
  22361. X
  22362. XThu May 31 19:25:36 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22363. X
  22364. X    * port.c  Use #ifdef sparc instead of #ifdef SPARC since
  22365. X    the lowercase version is defined, and the uppercase one isn't.
  22366. X
  22367. XTue May 22 11:49:18 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22368. X
  22369. X    * port.c (ck_malloc)  if size==0 pretend size=1
  22370. X        (ck_realloc)  if(!ptr) call ck_malloc instead.
  22371. X
  22372. XTue May 15 12:05:45 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22373. X
  22374. X    * diffarch.c (diff_archive)  If not f_absolute_paths, and attempt to
  22375. X    open a file listed in the archive fails, try /filename also.  This will
  22376. X    allow diff to open the wrong file if both /filename and filename exist,
  22377. X    but there's nothing we can do about that.
  22378. X
  22379. XFri May 11 16:17:43 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22380. X
  22381. X    * Makefile, Descripbe new -DMTIO option.
  22382. X
  22383. X    * buffer.c diffarch.c  Change ifdefs slightly, so that
  22384. X    -DMTIO will include sys/mtio.h even if USG is defined.
  22385. X    This is for HUPX and similar BSD/USG crossovers.
  22386. X
  22387. XTue May  8 13:14:54 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22388. X    * update.c (update_archive)  Call reset_eof() when appropriate.
  22389. X
  22390. X    * buffer.c (reset_eof)  New function, that turns of EOF flag, and
  22391. X    re-sets the ar_record and ar_last pointers.  This will allow
  22392. X    'tar rf non-existant-file' to not core-dump.
  22393. X
  22394. XFri May  4 14:05:31 1990  David J. MacKenzie  (djm at albert.ai.mit.edu)
  22395. X
  22396. X    * tar.c: Recognize the +sparse option.  It was documented, but
  22397. X    only the short form (-S) was actually recognized.
  22398. X
  22399. XTue Apr 17 21:34:14 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22400. X
  22401. X    * create.c  Don't access location 0 if ->dir_contents is null.
  22402. X
  22403. XWed Apr 11 17:30:03 EDT 1990 Jay Fenlason (hack@ai.mit.edu)
  22404. X
  22405. X    * buffer.c (flush_archive, close_archive, new_volume) Always check
  22406. X    the return value of rmtclose(), and only give a warning msg if it is
  22407. X    <0.  Some device drivers (including Sun floppy disk, and HP
  22408. X    streaming tape) return -1 after an IO error (or something like that.)
  22409. X
  22410. XFri Mar 23 00:06:30 1990  Jim Kingdon  (kingdon at mole.ai.mit.edu)
  22411. X
  22412. X    * tar.c (long_options): Make it so +append +extract +list +update
  22413. X    +catenate and +delete don't take arguments.
  22414. X
  22415. XMon Mar 12 13:33:53 EST 1990
  22416. X
  22417. X    * buffer.c (open_archive, fl_write) Set the mtime of the volume
  22418. X    header to the current time.
  22419. X
  22420. XWed Mar  7 14:10:10 EST 1990    Jay Fenlason (hack@ai.mit.edu)
  22421. X
  22422. X    * buffer.c  Fix +compress-block  A two character patch from
  22423. X    Juha Sarlin (juha@tds.kth.se)
  22424. X        Replace #ifdef __GNU__ with #ifdef __STDC__
  22425. X        (new_volume)  If open of new archive fails, ask again
  22426. X                (Is probably user error.)
  22427. X
  22428. X    * tar.c   Replace #ifdef __GNU__ with #ifdef __STDC__
  22429. X
  22430. X    * port.c  Clean up #ifdef and #defines a bit.
  22431. X        (quote_copy_string)  Sometimes the malloc'd buffer
  22432. X                would be up to two characters too short.
  22433. X
  22434. X    * extract.c (extract_archive) Don't declare ind static.
  22435. X
  22436. X    * create.c (dump_file)  Don't declare index_offset static.
  22437. X
  22438. X    * diffarch.c  Remove diff_name variable, and always use
  22439. X    head->header.name, which will always work, unlike diff_name, which
  22440. X    becomes trash when the next block is read in.
  22441. X
  22442. XThu Mar  1 13:43:30 EST 1990    Jay Fenlason (hack@wookumz.ai.mit.edu)
  22443. X
  22444. X    * Makefile Mention the -NO_REMOTE option.
  22445. X    * port.c Fix typo, and define WANT_FTRUNCATE on i386 machines.
  22446. X
  22447. XMon Feb 26 17:44:53 1990  Jim Kingdon  (kingdon at pogo.ai.mit.edu)
  22448. X
  22449. X    * getdate.y: Declare yylex and yyerror as static.
  22450. X    #define yyparse to getdate_yyparse.
  22451. X
  22452. XSun Feb 25 20:47:23 1990  David J. MacKenzie  (djm at albert.ai.mit.edu)
  22453. X
  22454. X    * tar.c: Remove +old option, since it is a valid abbreviation of
  22455. X    +old-archive, which does the same thing.
  22456. X    (describe): A few small cleanups in message.
  22457. X
  22458. XMon Feb  5 14:29:21 EST 1990    Jay Fenlason    (hack@wookumz)
  22459. X
  22460. X    * port.c  define LOSING_MSG on sparc, since doprnt_msg doesn't work.
  22461. X          Fix typo in #ifdef WANT_GETWD
  22462. X
  22463. XFri Jan 26 16:11:20 EST 1990    Jay Fenlason    (hack@wookumz)
  22464. X
  22465. X    1.08    Sparse file support added.  Also various other features.
  22466. X
  22467. X    * diffarch.c (compare_chunk)  Include correct arguments in
  22468. X    a call to fprintf() for an error msg.
  22469. X    (compare_chunks, compare_dir)  First argument is a long, not an int.
  22470. X
  22471. X    * tar.c (options)  Use tar variable (argv[0]) as the name to print
  22472. X     in an error msg, instead of a constant "tar".
  22473. X    (confirm)  Use external variable char TTY_NAME[] for name of file
  22474. X    to open for confirmation input.
  22475. X
  22476. X    * buffer.c (new_volume)  Ditto.
  22477. X
  22478. X    * port.c  Add declaration for TTY_NAME[].
  22479. X
  22480. X    * rmt.h  Add long declarations for lseek() and __rmt_lseek();
  22481. X
  22482. XTue Jan 23 14:06:21 EST 1990    Jay Fenlason (hack@wookumz)
  22483. X    * tar.c, create.c  Create the +newer-mtime option, which is like
  22484. X    +newer, but only looks for files whose mtime is newer than the
  22485. X    given date.
  22486. X
  22487. X    * rtape_lib.c  Make *both* instances of signal-handler stuff use
  22488. X    void (*foo)() on USG systems.
  22489. X
  22490. XThu Jan 11 14:03:45 EST 1990  Jay Fenlason  (hack@wookumz)
  22491. X
  22492. X    * getdate.y  Parse European dates of the form YYMMDD.
  22493. X    In ftime()  Init timezone by calling localtime(), and remember that
  22494. X    timezone is in seconds, but we want timeb->timezone to be in minutes.
  22495. X    This small patch from Joergen Haegg  (jh@aahas.se)
  22496. X
  22497. X    * rtape_lib.c (__rmt_open)  Also look for /usr/bsd/rsh.
  22498. X    Declare signal handler as returning void instead of int if USG is
  22499. X    defined.
  22500. X
  22501. X    * port.c Declare WANT_GETWD for SGI 4-D IRIS.
  22502. X
  22503. X    * Makefile  Include defines for SGI 4D version.  There are a simple
  22504. X    patch from Mike Muuss (mike@brl.mil).
  22505. X
  22506. X    * buffer.c (fl_read)  Work properly on broken Ultrix systems where
  22507. X    read() returns -1 with errno==ENOSPC on end of tape.  Correctly go
  22508. X    on to the next volume if f_multivol.
  22509. X
  22510. X    * list.c (list_archive,print_header)  Flush msg_file after printing
  22511. X    messages.
  22512. X
  22513. X    * port.c Delete unused references to alloca().
  22514. X    Don't crash if malloc() returns zero in quote_copy_string.
  22515. X    Flush stderr in msg() and msg_perror().
  22516. X
  22517. X    * tar.c  Flush msg_file after printing confirmation msg.
  22518. X
  22519. XWed Jan 10 01:58:46 1990  David J. MacKenzie  (djm at hobbes.ai.mit.edu)
  22520. X
  22521. X    * tar.c (main): Change -help option and references to it to +help,
  22522. X    and remove suggestion to run info (which is unreleased, so not
  22523. X    likely to be of any help).
  22524. X
  22525. XTue Jan  9 16:16:00 EST 1990    Jay Fenlason  (hack @wookumz)
  22526. X
  22527. X    * create.c (dump_file)  Close file descriptor if start_header()
  22528. X    fails.
  22529. X        (dump_file)  Change test for ./ ness to not think that
  22530. X    .{any character} is a ./  These are both trivial changes from
  22531. X    Piercarlo "Peter" Grandi  pcg%cs.aber.ac.uk@nsfnet-relay.ac.uk
  22532. X
  22533. X    * diffarch.c (diff_init)  Print correct number of bytes in error
  22534. X    message.
  22535. X
  22536. XTue Jan  9 03:19:49 1990  David J. MacKenzie  (djm at hobbes.ai.mit.edu)
  22537. X
  22538. X    * Makefile: Add comment at top noting that two source files also
  22539. X    contain #defines that might need to be changed by hand.
  22540. X
  22541. X    * create.c, diffarch.c, extract.c: Change L_SET to 0 in lseek
  22542. X    calls, because only BSD defines it.
  22543. X    * create.c (dump_file): Make sparse file checking code conditional
  22544. X    on BSD42 because it uses st_blocks, which the other systems lack.
  22545. X
  22546. XTue Jan  2 13:35:56 EST 1990 Jay Fenlason (hack@gnu)
  22547. X
  22548. X    * port.c (quote_copy_string)  Fix so it doesn't scramble memory if
  22549. X    the last character is non-printable.  A trivial fix from Kian-Tat Lim
  22550. X    (ktl@wag240.caltech.edu).
  22551. X
  22552. XTue Dec 19 11:19:37 1989  Jim Kingdon  (kingdon at pogo)
  22553. X
  22554. X    * port.c [BSD42]: Define DOPRNT_MSG.
  22555. X    tar.h [BSD42]: Do not prototype msg{,_perror}.
  22556. X
  22557. XFri Dec  8 11:02:47 EST 1989    Jay Fenlason (hack@gnu)
  22558. X
  22559. X    * create.c (dump_file)  Remove typo in msg.
  22560. X
  22561. XFri Dec  1 19:26:47 1989  David J. MacKenzie  (djm at trix)
  22562. X
  22563. X    * Makefile: Remove comments referring to certain systems lacking
  22564. X    getopt, since it is now provided always and needed by all systems.
  22565. X
  22566. X    * port.c: Remove copy of getopt.c, as it is now linked in
  22567. X    separately to always get the current version.
  22568. X
  22569. X    * tar.c: Rename +cat-tars option to +catenate or +concatenate, 
  22570. X    and +local-filesystem to +one-file-system (preferred by rms
  22571. X    and used in GNU cp for the same purpose).
  22572. X    (describe): Reflect changes.
  22573. X
  22574. XTue Nov 28 04:28:26 1989  David J. MacKenzie  (djm at hobbes.ai.mit.edu)
  22575. X
  22576. X    * port.c: Move declaration of alloca into #else /* sparc */
  22577. X    so it will compile on sparcs.
  22578. X
  22579. XMon Nov 27 15:17:08 1989  David J. MacKenzie  (djm at hobbes.ai.mit.edu)
  22580. X
  22581. X    * tar.c (options): Remove -version option (replaced by +version).
  22582. X    (describe): Mention long options.
  22583. X
  22584. XSat Nov 25 04:25:23 1989  David J. MacKenzie  (djm at hobbes.ai.mit.edu)
  22585. X
  22586. X    * getoldopt.c (getoldopt): Make `opt_index' argument a pointer to
  22587. X    an int, not char.
  22588. X
  22589. X    * tar.c: Modify long options per rms's suggestions:
  22590. X    Make preserve-permissions an alias for same-permissions.
  22591. X    Make preserve-order an alias for same-order.
  22592. X    Define preserve to mean both of those combined.
  22593. X    Make old an alias for old-archive.
  22594. X    Make portability an alias for old-archive, also.
  22595. X    Rename sym-links to dereference.
  22596. X    Rename gnudump to incremental.
  22597. X    Rename filename to file.
  22598. X    Make compare an alias for diff.  Leave diff but prefer compare.
  22599. X    Rename blocking-factor to block-size.
  22600. X    Rename chdir to directory.
  22601. X    Make uncompress an alias for compress.
  22602. X    Rename confirm to interactive.
  22603. X    Make get an alias for extract.
  22604. X    Rename volume-header to volume.
  22605. X
  22606. X    Also make +version an alias for -version.
  22607. X
  22608. X    (options): Shorten code that interprets long options by using
  22609. X    the equivalent short options' code.  This also makes it tons
  22610. X    easier to change the long options.
  22611. X
  22612. X    (describe): Make usage message more internally consistent
  22613. X    stylistically. 
  22614. X
  22615. XMon Nov 20 14:55:39 EST 1989    hack@ai.mit.edu
  22616. X
  22617. X    * list.c (read_and)  Call check_exclude() to see if the files
  22618. X    should be skipped on extract or list.
  22619. X
  22620. XThu Nov  9 18:59:32 1989  Jim Kingdon  (kingdon at hobbes.ai.mit.edu)
  22621. X
  22622. X    * buffer.c (fl_read): Fix typos in error message
  22623. X    "tar EOF not on block boundary".
  22624. X
  22625. XMon Oct 23 13:09:40 EDT 1989        (hack@ai.mit.edu)
  22626. X
  22627. X    * tar.c (long_options[])  Add an option for blocked compression.
  22628. X
  22629. XThu Oct 19 13:38:16 EDT 1989        (hack@ai.mit.edu)
  22630. X
  22631. X    * buffer.c (writeerror)  Print a more useful error msg.
  22632. X
  22633. XWed Sep 27 18:33:41 EDT 1989        (hack@ai.mit.edu)
  22634. X
  22635. X    * tar.c (main)  Mention "tar -help" if the luser types a non-workable
  22636. X    set of options.
  22637. X
  22638. XMon Sep 11 15:03:29 EDT 1989        (hack@ai.mit.edu)
  22639. X
  22640. X    * tar.c (options)  Have -F correctly set info_script.
  22641. X
  22642. XTue Aug 29 12:58:06 EDT 1989        (hack@ai.mit.edu)
  22643. X
  22644. X    * Makefile  Include ChangeLog in tar.tar and tar.tar.Z
  22645. X
  22646. XMon Aug 28 17:42:24 EDT 1989        (hack@ai.mit.edu)
  22647. X
  22648. X    * tar.c (options) Made -F imply -M
  22649. X    Also remind tar that the -f option takes an argument!
  22650. X
  22651. X    * Modified -F option to make it do what (I think) it
  22652. X    should.  e.g, if you say -F, tar won't send a msg to
  22653. X    msg_file and wait for a <return> It'll just run the program
  22654. X    it was given, and when the prog returns, the new tape had
  22655. X    *better* be ready. . .
  22656. X
  22657. X    * buffer.c (open_archive)  Give error message and abort if
  22658. X    the luser didn't give an archive name.
  22659. X
  22660. XFri Aug 25 20:05:27 EDT 1989        Joy Kendall (jak at hobbes)
  22661. X
  22662. X    * Added code to make a new option to run a specified script
  22663. X    at the end of each tape in a multi-volume backup.  Changed:
  22664. X    tar.c: made new switch, -F, and new long-named option,
  22665. X    "info-script".  Code is where you would expect.
  22666. X    tar.h: added flag f_run_script_at_end, and an extern char *
  22667. X    called info_script, which optarg gets set to.
  22668. X    buffer.c: line 1158 in new_volume(): if f_run_script_at_end
  22669. X    is set, we give info_script to system(), otherwise we do
  22670. X    what we've always done.  **FIXME** I'm not sure if that's all
  22671. X    that has to be done here.
  22672. X
  22673. XThu Aug 24 10:09:38 EDT 1989        Joy Kendall (jak at spiff)
  22674. X(These changes made over the course of 6/89 - 8/89)
  22675. X
  22676. X    * diffarch.c: diff_archive: Added switches for LF_SPARSE in the
  22677. X    case statements that needed it.  Also, skip any extended headers
  22678. X    if we need to when we skip over a file.  (need to change
  22679. X    the bit about, if the size doesn't agree AND the file is NOT
  22680. X    sparse, then there's a discrepancy, because I added another
  22681. X    field to the header which should be able to deal with the
  22682. X    sizes)   If the file is sparse, call the added routine
  22683. X    "diff_sparse_files" to compare.  Also added routine 
  22684. X    "fill_in_sparse_array".
  22685. X
  22686. X    * extract.c: extract_archive: added the switch LF_SPARSE
  22687. X    to the case statement as needed, and code to treat the 
  22688. X    sparse file.  At label "again_file", modified opening the
  22689. X    file to see if we should have O_APPEND be one of the modes.
  22690. X    Added code at label "extract_file" to call the new routine
  22691. X     "extract_sparse_file" when we have an LF_SPARSE flag.
  22692. X
  22693. X    Note: really should erase the commented-out code in there,
  22694. X    because it's confusing.
  22695. X
  22696. X    * update.c: made sure that if a file needed to be "skipped" 
  22697. X    over, it would check to see if the linkflag was sparse, and
  22698. X    if so, would then make sure to skip over any "extended 
  22699. X    headers" that might come after the header itself.  Do so by
  22700. X    calling "skip_extended_headers".
  22701. X
  22702. X    * create.c: create_archive: added code to detect a sparse
  22703. X    file when in the long case statement.  Added ways to detect
  22704. X    extended headers, and label "extend" (ack! should get rid of
  22705. X    that, is atrocious).  Call the new routine "finish_sparse_file"
  22706. X    if the linkflag is LF_SPARSE to write the info to the tape.
  22707. X    Also added routines "init_sparsearray", "deal_with_sparse",
  22708. X    "clear_buffer", "where_is_data", "zero_record", and 
  22709. X    "find_new_file_size".
  22710. X
  22711. X    * tar.h:  Added the #define's SPARSE_EXT_HDR and 
  22712. X    SPARSE_IN_HDR.  Added the struct sparse and the struct
  22713. X    sp_array.  Added the linkflag LF_SPARSE. Changed the tar
  22714. X     header in several ways:
  22715. X        - added an array of struct sparse's SPARSE_IN_HDR long
  22716. X        - added a char flag isextended
  22717. X        - added a char string realsize to store the true
  22718. X        size of a sparse file
  22719. X    Added another choice to the union record called a
  22720. X    struct extended_header, which is an array of 21 struct
  22721. X    sparse's and a char isextended flag.  Added flag
  22722. X    f_sparse_file to list of flags.
  22723. X
  22724. X    * tar.c: added long-named options to make tar compatible with
  22725. X    getopt_long, changed Makefile.
  22726. X
  22727. X... ... .. ..:..:.. ... ....    Jay Fenlason (hack@ai.mit.edu)
  22728. X
  22729. X    1.07    New version to go on beta tape with GCC 1.35
  22730. X    Better USG support.  Also support for __builtin_alloca
  22731. X    if we're compiling with GCC.
  22732. X    diffarch.c: Include the correct header files so MTIOCTOP
  22733. X    is defined.
  22734. X    tar.c:  Don't print the verbose list of options unless
  22735. X    given -help.  The list of options is *way* too long.
  22736. X
  22737. X    1.06    Use STDC_MSG if __STDC__ defined
  22738. X    ENXIO meand end-of-volume in archive (for the UNIX PC)
  22739. X    Added break after volume-header case (line 440) extract.c
  22740. X    Added patch from arnold@unix.cc.emory.edu to rtape_lib.c
  22741. X    Added f_absolute_paths option.
  22742. X    Deleted refereces to UN*X manual sections (dump(8), etc)
  22743. X    Fixed to not core-dump on illegal options
  22744. X    Modified msg_perror to call perror("") instead of perror(0)
  22745. X    patch so -X - works
  22746. X    Fixed tar.c so 'tar cf - -C dir' doesn't core-dump
  22747. X    tar.c (name_match): Fixed to chdir() to the appropriate
  22748. X    directory if the matching name's change_dir is set.  This
  22749. X    makes tar xv -C foo {files} work.
  22750. X
  22751. X    1.05    A fix to make confirm() work when the archive is on stdin
  22752. X    include 'extern FILE *msg_file;' in pr_mkdir(), and fix
  22753. X    tar.h to work with __STDC__
  22754. X
  22755. X    Added to port.c: mkdir() ftruncate()  Removed: lstat()
  22756. X    Fixed -G to work with -X
  22757. X    Another fix to tar.texinfo
  22758. X    Changed tar.c to say argv[0]":you must specify exactly ...
  22759. X    buffer.c: modified child_open() to keep tar from hanging when
  22760. X    it is done reading/writing a compressed archive
  22761. X    added fflush(msg_file) before printing error messages
  22762. X    create.c: fixed to make link_names non-absolute
  22763. X
  22764. X    1.04    Added functions msg() and msg_perror()  Modified all the
  22765. X    files to call them.  Also checked that all (I hope)
  22766. X    calls to msg_perror() have a valid errno value
  22767. X    (modified anno() to leave errno alone), etc
  22768. X    Re-fixed the -X option.  This time for sure. . .
  22769. X    re-modified the msg stuff.  flushed anno() completely
  22770. X    Modified the directory stuff so it should work on sysV boxes
  22771. X    added ftime() to getdate.y
  22772. X    Fixed un_quote_string() so it won't wedge on \" Also fixed
  22773. X    \ddd (like \123, etc)
  22774. X    More fixes to tar.texinfo
  22775. X
  22776. X    1.03    Fixed buffer.c so 'tar tzf NON_EXISTENT_FILE' returns an error
  22777. X    message instead of hanging forever
  22778. X    More fixes to tar.texinfo
  22779. X
  22780. X    1.02    Fixed tar.c so 'tar -h' and 'tar -v' don't cause core dump
  22781. X    Also fixed the 'usage' message to be more up-to-date.
  22782. X    Fixed diffarch.c so verify should compile without MTIOCTOP
  22783. X    defined
  22784. X
  22785. X    1.01    Fixed typoes in tar.texinfo
  22786. X    Fixed a bug in the #define for rmtcreat()
  22787. X    Fixed the -X option to not call realloc() of 0.
  22788. X
  22789. X    Version 1.00:  version.c added.  -version option added
  22790. X    Installed new version of the remote-tape library
  22791. X    Added -help option
  22792. X
  22793. XLocal Variables:
  22794. Xmode: indented-text
  22795. Xleft-margin: 8
  22796. Xversion-control: never
  22797. XEnd:
  22798. END_OF_FILE
  22799. if test 61978 -ne `wc -c <'ChangeLog'`; then
  22800.     echo shar: \"'ChangeLog'\" unpacked with wrong size!
  22801. fi
  22802. # end of 'ChangeLog'
  22803. fi
  22804. if test -f 'Makefile.in' -a "${1}" != "-c" ; then 
  22805.   echo shar: Will not clobber existing file \"'Makefile.in'\"
  22806. else
  22807. echo shar: Extracting \"'Makefile.in'\" \(6306 characters\)
  22808. sed "s/^X//" >'Makefile.in' <<'END_OF_FILE'
  22809. X# Un*x Makefile for GNU tar program.
  22810. X# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
  22811. X
  22812. X# This program is free software; you can redistribute it and/or modify
  22813. X# it under the terms of the GNU General Public License as published by
  22814. X# the Free Software Foundation; either version 2, or (at your option)
  22815. X# any later version.
  22816. X
  22817. X# This program is distributed in the hope that it will be useful,
  22818. X# but WITHOUT ANY WARRANTY; without even the implied warranty of
  22819. X# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  22820. X# GNU General Public License for more details.
  22821. X
  22822. X# You should have received a copy of the GNU General Public License
  22823. X# along with this program; if not, write to the Free Software
  22824. X# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  22825. X
  22826. X#### Start of system configuration section. ####
  22827. X
  22828. Xsrcdir = @srcdir@
  22829. XVPATH = @srcdir@
  22830. X
  22831. X# If you use gcc, you should either run the fixincludes script that
  22832. X# comes with it or else use gcc with the -traditional option.  Otherwise
  22833. X# ioctl calls will be compiled incorrectly on some systems.
  22834. XCC = @CC@
  22835. XYACC = @YACC@
  22836. XINSTALL = @INSTALL@
  22837. XINSTALL_PROGRAM = @INSTALL_PROGRAM@
  22838. XINSTALL_DATA = @INSTALL_DATA@
  22839. X
  22840. X# Things you might add to DEFS:
  22841. X# -DSTDC_HEADERS    If you have ANSI C headers and libraries.
  22842. X# -DHAVE_UNISTD_H    If you have unistd.h.
  22843. X# -DHAVE_STRING_H    If you don't have ANSI C headers but have string.h.
  22844. X# -DHAVE_LIMITS_H    If you have limits.h.
  22845. X# -DBSD42        If you have sys/dir.h (unless you use -DPOSIX),
  22846. X#            sys/file.h, and st_blocks in `struct stat'.
  22847. X# -DDIRENT        If you have dirent.h.
  22848. X# -DSYSNDIR        Old Xenix systems (sys/ndir.h).
  22849. X# -DSYSDIR        Old BSD systems (sys/dir.h).
  22850. X# -DNDIR        Old System V systems (ndir.h).
  22851. X# -DMAJOR_IN_MKDEV    If major, minor, makedev defined in sys/mkdev.h.
  22852. X# -DMAJOR_IN_SYSMACROS    If major, minor, makedev defined in sys/sysmacros.h.
  22853. X# -DRETSIGTYPE=int    If your signal handlers return int, not void.
  22854. X# -DHAVE_SYS_MTIO_H    If you have sys/mtio.h (magtape ioctls).
  22855. X# -DHAVE_SYS_GENTAPE_H    If you have sys/gentape.h (ISC magtape ioctls).
  22856. X# -DHAVE_NETDB_H    To use rexec for remote tape operations
  22857. X#            instead of forking rsh or remsh.
  22858. X# -DNO_REMOTE        If you have neither a remote shell nor rexec.
  22859. X# -DHAVE_VPRINTF    If you have vprintf function.
  22860. X# -DHAVE_DOPRNT        If you have _doprnt function (but lack vprintf).
  22861. X# -DHAVE_FTIME        If you have ftime system call.
  22862. X# -DHAVE_STRSTR        If you have strstr function.
  22863. X# -DHAVE_VALLOC        If you have valloc function.
  22864. X# -DHAVE_MKDIR        If you have mkdir and rmdir system calls.
  22865. X# -DHAVE_MKNOD        If you have mknod system call.
  22866. X# -DHAVE_RENAME     If you have rename system call.
  22867. X# -DHAVE_GETCWD        If not POSIX.1 but have getcwd function.
  22868. X# -DHAVE_FTRUNCATE    If you have ftruncate system call.
  22869. X# -DV7            On Version 7 Unix (not tested in a long time).
  22870. X# -DEMUL_OPEN3        If you lack a 3-argument version of open, and want
  22871. X#            to emulate it with system calls you do have.
  22872. X# -DNO_OPEN3        If you lack the 3-argument open and want to
  22873. X#            disable the tar -k option instead of emulating open.
  22874. X# -DXENIX        If you have sys/inode.h and need it to be included.
  22875. X
  22876. XDEF_AR_FILE = @DEF_AR_FILE@
  22877. XDEFBLOCKING = 20
  22878. XDEFS = @DEFS@ -DDEF_AR_FILE=\"$(DEF_AR_FILE)\" -DDEFBLOCKING=$(DEFBLOCKING)
  22879. X
  22880. X# Set this to rtapelib.o unless you defined NO_REMOTE, in which case
  22881. X# make it empty.
  22882. XRTAPELIB = @RTAPELIB@
  22883. XLIBS = @LIBS@
  22884. X
  22885. XCFLAGS = -g
  22886. XLDFLAGS = -g
  22887. X
  22888. Xprefix = /usr/local
  22889. Xexec_prefix = $(prefix)
  22890. X
  22891. X# Prefix for each installed program, normally empty or `g'.
  22892. Xbinprefix = 
  22893. X
  22894. X# The directory to install tar in.
  22895. Xbindir = $(exec_prefix)/bin
  22896. X
  22897. X# Where to put the rmt executable.
  22898. Xlibdir = /etc
  22899. X
  22900. X# The directory to install the info files in.
  22901. Xinfodir = $(prefix)/info
  22902. X
  22903. X#### End of system configuration section. ####
  22904. X
  22905. XSHELL = /bin/sh
  22906. X
  22907. XSRC1 =    tar.c create.c extract.c buffer.c getoldopt.c update.c gnu.c mangle.c
  22908. XSRC2 =  version.c list.c names.c diffarch.c port.c fnmatch.c getopt.c malloc.c
  22909. XSRC3 =  getopt1.c regex.c getdate.y getdate.c alloca.c
  22910. XSRCS =    $(SRC1) $(SRC2) $(SRC3)
  22911. XOBJ1 =    tar.o create.o extract.o buffer.o getoldopt.o update.o gnu.o mangle.o
  22912. XOBJ2 =    version.o list.o names.o diffarch.o port.o fnmatch.o getopt.o @MALLOC@
  22913. XOBJ3 =  getopt1.o regex.o getdate.o $(RTAPELIB) @ALLOCA@
  22914. XOBJS =    $(OBJ1) $(OBJ2) $(OBJ3)
  22915. XAUX =   README INSTALL NEWS COPYING ChangeLog Makefile.in makefile.pc \
  22916. X    configure configure.in \
  22917. X    tar.h fnmatch.h pathmax.h port.h open3.h getopt.h regex.h \
  22918. X    rmt.h rmt.c rtapelib.c \
  22919. X    msd_dir.h msd_dir.c tcexparg.c \
  22920. X    level-0 level-1 backup-specs dump-remind testpad.c getpagesize.h
  22921. X#    tar.texinfo tar.info* texinfo.tex \
  22922. X
  22923. Xall:    @PROGS@ 
  22924. X# tar.info
  22925. X
  22926. X.c.o:
  22927. X    $(CC) -c $(CFLAGS) $(CPPFLAGS) $(DEFS) -I$(srcdir) -I. $<
  22928. X
  22929. Xtar:    $(OBJS)
  22930. X    $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS)
  22931. X
  22932. Xrmt:    rmt.c
  22933. X    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(srcdir)/rmt.c $(LIBS)
  22934. X
  22935. Xtar.info: tar.texinfo
  22936. X    makeinfo $(srcdir)/tar.texinfo
  22937. X
  22938. Xinstall: all
  22939. X    $(INSTALL_PROGRAM) tar $(bindir)/$(binprefix)tar
  22940. X    -test ! -f rmt || $(INSTALL_PROGRAM) rmt $(libdir)/rmt
  22941. X#    for file in $(srcdir)/tar.info*; \
  22942. X#    do $(INSTALL_DATA) $$file $(infodir)/$$file; \
  22943. X#    done
  22944. X
  22945. Xuninstall:
  22946. X    rm -f $(bindir)/$(binprefix)tar    $(infodir)/tar.info*
  22947. X    -rm -f $(libdir)/rmt
  22948. X
  22949. X$(OBJS): tar.h pathmax.h port.h testpad.h
  22950. Xregex.o buffer.o tar.o: regex.h
  22951. Xtar.o fnmatch.o: fnmatch.h
  22952. X
  22953. Xgetdate.c: getdate.y
  22954. X    $(YACC) $(srcdir)/getdate.y
  22955. X    mv y.tab.c getdate.c
  22956. X# getdate.y has 8 shift/reduce conflicts.
  22957. X
  22958. Xtestpad.h: testpad
  22959. X    ./testpad
  22960. X
  22961. Xtestpad: testpad.o
  22962. X    $(CC) -o $@ testpad.o
  22963. X
  22964. XTAGS:    $(SRCS)
  22965. X    etags $(SRCS)
  22966. X
  22967. Xclean:
  22968. X    rm -f *.o tar rmt testpad testpad.h core
  22969. X
  22970. Xmostlyclean: clean
  22971. X
  22972. Xdistclean: clean
  22973. X    rm -f Makefile config.status
  22974. X
  22975. Xrealclean: distclean
  22976. X    rm -f TAGS *.info* getdate.c y.tab.c
  22977. X
  22978. Xshar: $(SRCS) $(AUX)
  22979. X    shar $(SRCS) $(AUX) | gzip > tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c`.shar.z
  22980. X
  22981. Xdist: $(SRCS) $(AUX)
  22982. X    echo tar-`sed -e '/version_string/!d' -e 's/[^0-9.]*\([0-9.]*\).*/\1/' -e q version.c` > .fname
  22983. X    -rm -rf `cat .fname`
  22984. X    mkdir `cat .fname`
  22985. X    for file in $(SRCS) $(AUX); do \
  22986. X          ln $$file `cat .fname` || cp $$file `cat .fname`; done
  22987. X    tar chzf `cat .fname`.tar.z `cat .fname`
  22988. X    -rm -rf `cat .fname` .fname
  22989. X
  22990. Xtar.zoo: $(SRCS) $(AUX)
  22991. X    -rm -rf tmp.dir
  22992. X    -mkdir tmp.dir
  22993. X    -rm tar.zoo
  22994. X    for X in $(SRCS) $(AUX) ; do echo $$X ; sed 's/$$//' $$X > tmp.dir/$$X ; done
  22995. X    cd tmp.dir ; zoo aM ../tar.zoo *
  22996. X    -rm -rf tmp.dir
  22997. X
  22998. X# Prevent GNU make v3 from overflowing arg limit on SysV.
  22999. X.NOEXPORT:
  23000. END_OF_FILE
  23001. if test 6306 -ne `wc -c <'Makefile.in'`; then
  23002.     echo shar: \"'Makefile.in'\" unpacked with wrong size!
  23003. fi
  23004. # end of 'Makefile.in'
  23005. fi
  23006. if test -f 'makefile.pc' -a "${1}" != "-c" ; then 
  23007.   echo shar: Will not clobber existing file \"'makefile.pc'\"
  23008. else
  23009. echo shar: Extracting \"'makefile.pc'\" \(1700 characters\)
  23010. sed "s/^X//" >'makefile.pc' <<'END_OF_FILE'
  23011. X# Makefile for GNU tar on MS-DOS.
  23012. X# Copyright (C) 1991 Free Software Foundation, Inc.
  23013. X
  23014. X# This program is free software; you can redistribute it and/or modify
  23015. X# it under the terms of the GNU General Public License as published by
  23016. X# the Free Software Foundation; either version 2, or (at your option)
  23017. X# any later version.
  23018. X
  23019. X# This program is distributed in the hope that it will be useful,
  23020. X# but WITHOUT ANY WARRANTY; without even the implied warranty of
  23021. X# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23022. X# GNU General Public License for more details.
  23023. X
  23024. X# You should have received a copy of the GNU General Public License
  23025. X# along with this program; if not, write to the Free Software
  23026. X# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23027. X
  23028. XCC = bcc
  23029. XRM = rm -f
  23030. X
  23031. XMODEL = m
  23032. XDEFS = -DNONAMES -DNO_REMOTE -DSTDC_HEADERS=1 -m$(MODEL) -Dmain=_main
  23033. XLIBS =
  23034. X
  23035. XCFLAGS = $(DEFS)
  23036. XLDFLAGS = -m$(MODEL)
  23037. X
  23038. XOBJ1 =    tar.obj create.obj extract.obj buffer.obj getoldopt.obj update.obj gnu.obj mangle.obj
  23039. XOBJ2 =    version.obj list.obj names.obj diffarch.obj port.obj fnmatch.obj getopt.obj
  23040. XOBJ3 =  getopt1.obj regex.obj getdate.obj alloca.obj tcexparg.obj msd_dir.obj
  23041. XOBJS =    $(OBJ1) $(OBJ2) $(OBJ3)
  23042. X
  23043. Xall:    tar
  23044. X
  23045. Xtar:    testpad.h getdate.c $(OBJS)
  23046. X    $(RM) testpad.obj
  23047. X    $(CC) $(LDFLAGS) -etar *.obj $(LIBS)
  23048. X
  23049. X.c.obj:
  23050. X    $(CC) -c $(CFLAGS) $<
  23051. X
  23052. X# For some reason, Borland C++ 3.1 chokes on this file when given
  23053. X# the full set of -D options.
  23054. Xgetoldopt.obj: getoldopt.c
  23055. X    $(CC) -c -m$(MODEL) -DSTDC_HEADERS getoldopt.c
  23056. X
  23057. Xtestpad.h: testpad.exe
  23058. X    testpad
  23059. X
  23060. Xtestpad.exe: testpad.c
  23061. X    $(CC) $(LDFLAGS) -etestpad testpad.c $(LIBS)
  23062. X
  23063. Xclean:
  23064. X    $(RM) errs *.obj tar testpad testpad.h
  23065. X
  23066. Xmostlyclean: clean
  23067. X
  23068. Xdistclean: clean
  23069. X
  23070. Xrealclean: clean
  23071. END_OF_FILE
  23072. if test 1700 -ne `wc -c <'makefile.pc'`; then
  23073.     echo shar: \"'makefile.pc'\" unpacked with wrong size!
  23074. fi
  23075. # end of 'makefile.pc'
  23076. fi
  23077. if test -f 'configure' -a "${1}" != "-c" ; then 
  23078.   echo shar: Will not clobber existing file \"'configure'\"
  23079. else
  23080. echo shar: Extracting \"'configure'\" \(19657 characters\)
  23081. sed "s/^X//" >'configure' <<'END_OF_FILE'
  23082. X#!/bin/sh
  23083. X# Guess values for system-dependent variables and create Makefiles.
  23084. X# Generated automatically using autoconf.
  23085. X# Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
  23086. X
  23087. X# This program is free software; you can redistribute it and/or modify
  23088. X# it under the terms of the GNU General Public License as published by
  23089. X# the Free Software Foundation; either version 2, or (at your option)
  23090. X# any later version.
  23091. X
  23092. X# This program is distributed in the hope that it will be useful,
  23093. X# but WITHOUT ANY WARRANTY; without even the implied warranty of
  23094. X# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  23095. X# GNU General Public License for more details.
  23096. X
  23097. X# You should have received a copy of the GNU General Public License
  23098. X# along with this program; if not, write to the Free Software
  23099. X# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23100. X
  23101. X# Usage: configure [--srcdir=DIR] [--host=HOST] [--gas] [--nfp] [--no-create]
  23102. X#        [--prefix=PREFIX] [--exec-prefix=PREFIX] [--with-PACKAGE] [TARGET]
  23103. X# Ignores all args except --srcdir, --prefix, --exec-prefix, --no-create, and
  23104. X# --with-PACKAGE unless this script has special code to handle it.
  23105. X
  23106. X
  23107. Xfor arg
  23108. Xdo
  23109. X  # Handle --exec-prefix with a space before the argument.
  23110. X  if test x$next_exec_prefix = xyes; then exec_prefix=$arg; next_exec_prefix=
  23111. X  # Handle --host with a space before the argument.
  23112. X  elif test x$next_host = xyes; then next_host=
  23113. X  # Handle --prefix with a space before the argument.
  23114. X  elif test x$next_prefix = xyes; then prefix=$arg; next_prefix=
  23115. X  # Handle --srcdir with a space before the argument.
  23116. X  elif test x$next_srcdir = xyes; then srcdir=$arg; next_srcdir=
  23117. X  else
  23118. X    case $arg in
  23119. X     # For backward compatibility, also recognize exact --exec_prefix.
  23120. X     -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* | --exec=* | --exe=* | --ex=* | --e=*)
  23121. X    exec_prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;;
  23122. X     -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- | --exec | --exe | --ex | --e)
  23123. X    next_exec_prefix=yes ;;
  23124. X
  23125. X     -gas | --gas | --ga | --g) ;;
  23126. X
  23127. X     -host=* | --host=* | --hos=* | --ho=* | --h=*) ;;
  23128. X     -host | --host | --hos | --ho | --h)
  23129. X    next_host=yes ;;
  23130. X
  23131. X     -nfp | --nfp | --nf) ;;
  23132. X
  23133. X     -no-create | --no-create | --no-creat | --no-crea | --no-cre | --no-cr | --no-c | --no- | --no)
  23134. X        no_create=1 ;;
  23135. X
  23136. X     -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
  23137. X    prefix=`echo $arg | sed 's/[-a-z_]*=//'` ;;
  23138. X     -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
  23139. X    next_prefix=yes ;;
  23140. X
  23141. X     -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=* | --s=*)
  23142. X    srcdir=`echo $arg | sed 's/[-a-z_]*=//'` ;;
  23143. X     -srcdir | --srcdir | --srcdi | --srcd | --src | --sr | --s)
  23144. X    next_srcdir=yes ;;
  23145. X
  23146. X     -with-* | --with-*)
  23147. X       package=`echo $arg|sed 's/-*with-//'`
  23148. X       # Delete all the valid chars; see if any are left.
  23149. X       if test -n "`echo $package|sed 's/[-a-zA-Z0-9_]*//g'`"; then
  23150. X         echo "configure: $package: invalid package name" >&2; exit 1
  23151. X       fi
  23152. X       eval "with_`echo $package|sed s/-/_/g`=1" ;;
  23153. X
  23154. X     *) ;;
  23155. X    esac
  23156. X  fi
  23157. Xdone
  23158. X
  23159. Xtrap 'rm -f conftest* core; exit 1' 1 3 15
  23160. X
  23161. Xrm -f conftest*
  23162. Xcompile='${CC-cc} $CFLAGS $DEFS conftest.c -o conftest $LIBS >/dev/null 2>&1'
  23163. X
  23164. X# A filename unique to this package, relative to the directory that
  23165. X# configure is in, which we can look for to find out if srcdir is correct.
  23166. Xunique_file=tar.h
  23167. X
  23168. X# Find the source files, if location was not specified.
  23169. Xif test -z "$srcdir"; then
  23170. X  srcdirdefaulted=yes
  23171. X  # Try the directory containing this script, then `..'.
  23172. X  prog=$0
  23173. X  confdir=`echo $prog|sed 's%/[^/][^/]*$%%'`
  23174. X  test "X$confdir" = "X$prog" && confdir=.
  23175. X  srcdir=$confdir
  23176. X  if test ! -r $srcdir/$unique_file; then
  23177. X    srcdir=..
  23178. X  fi
  23179. Xfi
  23180. Xif test ! -r $srcdir/$unique_file; then
  23181. X  if test x$srcdirdefaulted = xyes; then
  23182. X    echo "configure: Can not find sources in \`${confdir}' or \`..'." 1>&2
  23183. X  else
  23184. X    echo "configure: Can not find sources in \`${srcdir}'." 1>&2
  23185. X  fi
  23186. X  exit 1
  23187. Xfi
  23188. X# Preserve a srcdir of `.' to avoid automounter screwups with pwd.
  23189. X# But we can't avoid them for `..', to make subdirectories work.
  23190. Xcase $srcdir in
  23191. X  .|/*|~*) ;;
  23192. X  *) srcdir=`cd $srcdir; pwd` ;; # Make relative path absolute.
  23193. Xesac
  23194. X
  23195. XPROGS="tar"
  23196. Xif test -z "$CC"; then
  23197. X  echo checking for gcc
  23198. X  saveifs="$IFS"; IFS="${IFS}:"
  23199. X  for dir in $PATH; do
  23200. X    test -z "$dir" && dir=.
  23201. X    if test -f $dir/gcc; then
  23202. X      CC="gcc"
  23203. X      break
  23204. X    fi
  23205. X  done
  23206. X  IFS="$saveifs"
  23207. Xfi
  23208. Xtest -z "$CC" && CC="cc"
  23209. X
  23210. X# Find out if we are using GNU C, under whatever name.
  23211. Xcat > conftest.c <<EOF
  23212. X#ifdef __GNUC__
  23213. X  yes
  23214. X#endif
  23215. XEOF
  23216. X${CC-cc} -E conftest.c > conftest.out 2>&1
  23217. Xif egrep yes conftest.out >/dev/null 2>&1; then
  23218. X  GCC=1 # For later tests.
  23219. Xfi
  23220. Xrm -f conftest*
  23221. X
  23222. Xecho checking how to run the C preprocessor
  23223. Xif test -z "$CPP"; then
  23224. X  CPP='${CC-cc} -E'
  23225. X  cat > conftest.c <<EOF
  23226. X#include <stdio.h>
  23227. XEOF
  23228. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23229. Xif test -z "$err"; then
  23230. X  :
  23231. Xelse
  23232. X  CPP=/lib/cpp
  23233. Xfi
  23234. Xrm -f conftest*
  23235. Xfi
  23236. X
  23237. Xif test -n "$GCC"; then
  23238. X  echo checking whether -traditional is needed
  23239. X  pattern="Autoconf.*'x'"
  23240. X  prog='#include <sgtty.h>
  23241. XAutoconf TIOCGETP'
  23242. X  cat > conftest.c <<EOF
  23243. X$prog
  23244. XEOF
  23245. Xeval "$CPP $DEFS conftest.c > conftest.out 2>&1"
  23246. Xif egrep "$pattern" conftest.out >/dev/null 2>&1; then
  23247. X  need_trad=1
  23248. Xfi
  23249. Xrm -f conftest*
  23250. X
  23251. X
  23252. X  if test -z "$need_trad"; then
  23253. X    prog='#include <termio.h>
  23254. XAutoconf TCGETA'
  23255. X    cat > conftest.c <<EOF
  23256. X$prog
  23257. XEOF
  23258. Xeval "$CPP $DEFS conftest.c > conftest.out 2>&1"
  23259. Xif egrep "$pattern" conftest.out >/dev/null 2>&1; then
  23260. X  need_trad=1
  23261. Xfi
  23262. Xrm -f conftest*
  23263. X
  23264. X  fi
  23265. X  test -n "$need_trad" && CC="$CC -traditional"
  23266. Xfi
  23267. X
  23268. X# Make sure to not get the incompatible SysV /etc/install and
  23269. X# /usr/sbin/install, which might be in PATH before a BSD-like install,
  23270. X# or the SunOS /usr/etc/install directory, or the AIX /bin/install,
  23271. X# or the AFS install, which mishandles nonexistent args.  (Sigh.)
  23272. Xif test -z "$INSTALL"; then
  23273. X  echo checking for install
  23274. X  saveifs="$IFS"; IFS="${IFS}:"
  23275. X  for dir in $PATH; do
  23276. X    test -z "$dir" && dir=.
  23277. X    case $dir in
  23278. X    /etc|/usr/sbin|/usr/etc|/usr/afsws/bin) ;;
  23279. X    *)
  23280. X      if test -f $dir/install; then
  23281. X    if grep dspmsg $dir/install >/dev/null 2>&1; then
  23282. X      : # AIX
  23283. X    else
  23284. X      INSTALL="$dir/install -c"
  23285. X      INSTALL_PROGRAM='$(INSTALL)'
  23286. X      INSTALL_DATA='$(INSTALL) -m 644'
  23287. X      break
  23288. X    fi
  23289. X      fi
  23290. X      ;;
  23291. X    esac
  23292. X  done
  23293. X  IFS="$saveifs"
  23294. Xfi
  23295. XINSTALL=${INSTALL-cp}
  23296. XINSTALL_PROGRAM=${INSTALL_PROGRAM-'$(INSTALL)'}
  23297. XINSTALL_DATA=${INSTALL_DATA-'$(INSTALL)'}
  23298. X
  23299. Xif test -z "$YACC"; then
  23300. X  echo checking for bison
  23301. X  saveifs="$IFS"; IFS="${IFS}:"
  23302. X  for dir in $PATH; do
  23303. X    test -z "$dir" && dir=.
  23304. X    if test -f $dir/bison; then
  23305. X      YACC="bison -y"
  23306. X      break
  23307. X    fi
  23308. X  done
  23309. X  IFS="$saveifs"
  23310. Xfi
  23311. Xtest -z "$YACC" && YACC=""
  23312. X
  23313. Xif test -z "$YACC"; then
  23314. X  echo checking for byacc
  23315. X  saveifs="$IFS"; IFS="${IFS}:"
  23316. X  for dir in $PATH; do
  23317. X    test -z "$dir" && dir=.
  23318. X    if test -f $dir/byacc; then
  23319. X      YACC="byacc"
  23320. X      break
  23321. X    fi
  23322. X  done
  23323. X  IFS="$saveifs"
  23324. Xfi
  23325. Xtest -z "$YACC" && YACC="yacc"
  23326. X
  23327. X
  23328. Xecho checking for AIX
  23329. Xcat > conftest.c <<EOF
  23330. X#ifdef _AIX
  23331. X  yes
  23332. X#endif
  23333. X
  23334. XEOF
  23335. Xeval "$CPP $DEFS conftest.c > conftest.out 2>&1"
  23336. Xif egrep "yes" conftest.out >/dev/null 2>&1; then
  23337. X  DEFS="$DEFS -D_ALL_SOURCE=1"
  23338. Xfi
  23339. Xrm -f conftest*
  23340. X
  23341. X
  23342. Xecho checking for minix/config.h
  23343. Xcat > conftest.c <<EOF
  23344. X#include <minix/config.h>
  23345. XEOF
  23346. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23347. Xif test -z "$err"; then
  23348. X  MINIX=1
  23349. Xfi
  23350. Xrm -f conftest*
  23351. X
  23352. X# The Minix shell can't assign to the same variable on the same line!
  23353. Xif test -n "$MINIX"; then
  23354. X  DEFS="$DEFS -D_POSIX_SOURCE=1"
  23355. X  DEFS="$DEFS -D_POSIX_1_SOURCE=2"
  23356. X  DEFS="$DEFS -D_MINIX=1"
  23357. Xfi
  23358. X
  23359. Xecho checking for POSIXized ISC
  23360. Xif test -d /etc/conf/kconfig.d &&
  23361. X  grep _POSIX_VERSION /usr/include/sys/unistd.h >/dev/null 2>&1
  23362. Xthen
  23363. X  ISC=1 # If later tests want to check for ISC.
  23364. X  DEFS="$DEFS -D_POSIX_SOURCE=1"
  23365. X  if test -n "$GCC"; then
  23366. X    CC="$CC -posix"
  23367. X  else
  23368. X    CC="$CC -Xp"
  23369. X  fi
  23370. Xfi
  23371. X
  23372. Xecho checking for return type of signal handlers
  23373. Xcat > conftest.c <<EOF
  23374. X#include <sys/types.h>
  23375. X#include <signal.h>
  23376. X#ifdef signal
  23377. X#undef signal
  23378. X#endif
  23379. Xextern void (*signal ()) ();
  23380. Xmain() { exit(0); } 
  23381. Xt() { int i; }
  23382. XEOF
  23383. Xif eval $compile; then
  23384. X  DEFS="$DEFS -DRETSIGTYPE=void"
  23385. Xelse
  23386. X  DEFS="$DEFS -DRETSIGTYPE=int"
  23387. Xfi
  23388. Xrm -f conftest*
  23389. X
  23390. X
  23391. Xecho checking for size_t in sys/types.h
  23392. Xecho '#include <sys/types.h>' > conftest.c
  23393. Xeval "$CPP $DEFS conftest.c > conftest.out 2>&1"
  23394. Xif egrep "size_t" conftest.out >/dev/null 2>&1; then
  23395. X  :
  23396. Xelse 
  23397. X  DEFS="$DEFS -Dsize_t=unsigned"
  23398. Xfi
  23399. Xrm -f conftest*
  23400. X
  23401. Xecho checking for major, minor and makedev header
  23402. Xcat > conftest.c <<EOF
  23403. X#include <sys/types.h>
  23404. Xmain() { exit(0); } 
  23405. Xt() { return makedev(0, 0); }
  23406. XEOF
  23407. Xif eval $compile; then
  23408. X  makedev=1
  23409. Xfi
  23410. Xrm -f conftest*
  23411. X
  23412. Xif test -z "$makedev"; then
  23413. Xecho checking for sys/mkdev.h
  23414. Xcat > conftest.c <<EOF
  23415. X#include <sys/mkdev.h>
  23416. XEOF
  23417. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23418. Xif test -z "$err"; then
  23419. X  DEFS="$DEFS -DMAJOR_IN_MKDEV=1" makedev=1
  23420. Xfi
  23421. Xrm -f conftest*
  23422. X
  23423. Xfi
  23424. Xif test -z "$makedev"; then
  23425. Xecho checking for sys/sysmacros.h
  23426. Xcat > conftest.c <<EOF
  23427. X#include <sys/sysmacros.h>
  23428. XEOF
  23429. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23430. Xif test -z "$err"; then
  23431. X  DEFS="$DEFS -DMAJOR_IN_SYSMACROS=1"
  23432. Xfi
  23433. Xrm -f conftest*
  23434. X
  23435. Xfi
  23436. X
  23437. Xecho checking for directory library header
  23438. Xecho checking for dirent.h
  23439. Xcat > conftest.c <<EOF
  23440. X#include <dirent.h>
  23441. XEOF
  23442. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23443. Xif test -z "$err"; then
  23444. X  DEFS="$DEFS -DDIRENT=1" dirheader=dirent.h
  23445. Xfi
  23446. Xrm -f conftest*
  23447. X
  23448. Xif test -z "$dirheader"; then
  23449. Xecho checking for sys/ndir.h
  23450. Xcat > conftest.c <<EOF
  23451. X#include <sys/ndir.h>
  23452. XEOF
  23453. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23454. Xif test -z "$err"; then
  23455. X  DEFS="$DEFS -DSYSNDIR=1" dirheader=sys/ndir.h
  23456. Xfi
  23457. Xrm -f conftest*
  23458. X
  23459. Xfi
  23460. Xif test -z "$dirheader"; then
  23461. Xecho checking for sys/dir.h
  23462. Xcat > conftest.c <<EOF
  23463. X#include <sys/dir.h>
  23464. XEOF
  23465. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23466. Xif test -z "$err"; then
  23467. X  DEFS="$DEFS -DSYSDIR=1" dirheader=sys/dir.h
  23468. Xfi
  23469. Xrm -f conftest*
  23470. X
  23471. Xfi
  23472. Xif test -z "$dirheader"; then
  23473. Xecho checking for ndir.h
  23474. Xcat > conftest.c <<EOF
  23475. X#include <ndir.h>
  23476. XEOF
  23477. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23478. Xif test -z "$err"; then
  23479. X  DEFS="$DEFS -DNDIR=1" dirheader=ndir.h
  23480. Xfi
  23481. Xrm -f conftest*
  23482. X
  23483. Xfi
  23484. X
  23485. Xecho checking for closedir return value
  23486. Xcat > conftest.c <<EOF
  23487. X#include <sys/types.h>
  23488. X#include <$dirheader>
  23489. Xint closedir(); main() { exit(0); }
  23490. XEOF
  23491. Xeval $compile
  23492. Xif test -s conftest && (./conftest; exit) 2>/dev/null; then
  23493. X  :
  23494. Xelse
  23495. X  DEFS="$DEFS -DVOID_CLOSEDIR=1"
  23496. Xfi
  23497. Xrm -f conftest*
  23498. X
  23499. X# The 3-argument open happens to go along with the O_* defines,
  23500. X# which are easier to check for.
  23501. Xecho checking for fcntl.h
  23502. Xcat > conftest.c <<EOF
  23503. X#include <fcntl.h>
  23504. XEOF
  23505. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23506. Xif test -z "$err"; then
  23507. X  open_header=fcntl.h
  23508. Xelse
  23509. X  open_header=sys/file.h
  23510. Xfi
  23511. Xrm -f conftest*
  23512. X
  23513. Xecho checking for 3-argument open
  23514. Xcat > conftest.c <<EOF
  23515. X#include <$open_header>
  23516. Xmain() { exit(0); } 
  23517. Xt() { int x = O_RDONLY; }
  23518. XEOF
  23519. Xif eval $compile; then
  23520. X  :
  23521. Xelse
  23522. X  DEFS="$DEFS -DEMUL_OPEN3=1"
  23523. Xfi
  23524. Xrm -f conftest*
  23525. X
  23526. Xecho checking for remote tape and socket header files
  23527. Xecho checking for sys/mtio.h
  23528. Xcat > conftest.c <<EOF
  23529. X#include <sys/mtio.h>
  23530. XEOF
  23531. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23532. Xif test -z "$err"; then
  23533. X  DEFS="$DEFS -DHAVE_SYS_MTIO_H=1" have_mtio=1
  23534. Xfi
  23535. Xrm -f conftest*
  23536. X
  23537. Xif test -n "$have_mtio"; then
  23538. Xcat > conftest.c <<EOF
  23539. X#include <sgtty.h>
  23540. X#include <sys/socket.h>
  23541. XEOF
  23542. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23543. Xif test -z "$err"; then
  23544. X  PROGS="$PROGS rmt"
  23545. Xfi
  23546. Xrm -f conftest*
  23547. Xfi
  23548. X
  23549. Xecho checking for remote shell
  23550. Xif test -f /usr/ucb/rsh || test -f /usr/bin/remsh || test -f /usr/bin/rsh ||
  23551. X  test -f /usr/bsd/rsh || test -f /usr/bin/nsh; then
  23552. X  RTAPELIB=rtapelib.o
  23553. Xelse
  23554. X  echo checking for netdb.h
  23555. Xcat > conftest.c <<EOF
  23556. X#include <netdb.h>
  23557. XEOF
  23558. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23559. Xif test -z "$err"; then
  23560. X  DEFS="$DEFS -DHAVE_NETDB_H=1" RTAPELIB=rtapelib.o
  23561. Xelse
  23562. X  DEFS="$DEFS -DNO_REMOTE=1"
  23563. Xfi
  23564. Xrm -f conftest*
  23565. X
  23566. Xfi
  23567. X
  23568. Xecho checking for ANSI C header files
  23569. Xcat > conftest.c <<EOF
  23570. X#include <stdlib.h>
  23571. X#include <stdarg.h>
  23572. X#include <string.h>
  23573. X#include <float.h>
  23574. XEOF
  23575. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23576. Xif test -z "$err"; then
  23577. X  # SunOS string.h does not declare mem*, contrary to ANSI.
  23578. Xecho '#include <string.h>' > conftest.c
  23579. Xeval "$CPP $DEFS conftest.c > conftest.out 2>&1"
  23580. Xif egrep "memchr" conftest.out >/dev/null 2>&1; then
  23581. X  # SGI's /bin/cc from Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
  23582. Xcat > conftest.c <<EOF
  23583. X#include <ctype.h>
  23584. X#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
  23585. X#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
  23586. X#define XOR(e,f) (((e) && !(f)) || (!(e) && (f)))
  23587. Xint main () { int i; for (i = 0; i < 256; i++)
  23588. Xif (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
  23589. Xexit (0); }
  23590. X
  23591. XEOF
  23592. Xeval $compile
  23593. Xif test -s conftest && (./conftest; exit) 2>/dev/null; then
  23594. X  DEFS="$DEFS -DSTDC_HEADERS=1"
  23595. Xfi
  23596. Xrm -f conftest*
  23597. Xfi
  23598. Xrm -f conftest*
  23599. X
  23600. Xfi
  23601. Xrm -f conftest*
  23602. X
  23603. Xecho checking for unistd.h
  23604. Xcat > conftest.c <<EOF
  23605. X#include <unistd.h>
  23606. XEOF
  23607. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23608. Xif test -z "$err"; then
  23609. X  DEFS="$DEFS -DHAVE_UNISTD_H=1"
  23610. Xfi
  23611. Xrm -f conftest*
  23612. X
  23613. Xecho checking for getgrgid declaration
  23614. Xecho '#include <grp.h>' > conftest.c
  23615. Xeval "$CPP $DEFS conftest.c > conftest.out 2>&1"
  23616. Xif egrep "getgrgid" conftest.out >/dev/null 2>&1; then
  23617. X  DEFS="$DEFS -DHAVE_GETGRGID=1"
  23618. Xfi
  23619. Xrm -f conftest*
  23620. X
  23621. Xecho checking for getpwuid declaration
  23622. Xecho '#include <pwd.h>' > conftest.c
  23623. Xeval "$CPP $DEFS conftest.c > conftest.out 2>&1"
  23624. Xif egrep "getpwuid" conftest.out >/dev/null 2>&1; then
  23625. X  DEFS="$DEFS -DHAVE_GETPWUID=1"
  23626. Xfi
  23627. Xrm -f conftest*
  23628. X
  23629. Xfor hdr in string.h limits.h
  23630. Xdo
  23631. Xtrhdr=HAVE_`echo $hdr | tr '[a-z]./' '[A-Z]__'`
  23632. Xecho checking for ${hdr}
  23633. Xcat > conftest.c <<EOF
  23634. X#include <${hdr}>
  23635. XEOF
  23636. Xerr=`eval "$CPP $DEFS conftest.c 2>&1 >/dev/null"`
  23637. Xif test -z "$err"; then
  23638. X  DEFS="$DEFS -D${trhdr}=1"
  23639. Xfi
  23640. Xrm -f conftest*
  23641. Xdone
  23642. X
  23643. Xecho checking default archive
  23644. X# This might guess wrong, but it's not very important.
  23645. Xfor dev in rmt8 rmt0 rmt0h rct0 rst0 tape rct/c7d0s2
  23646. Xdo
  23647. X  if test -n "`ls /dev/$dev 2>/dev/null`"; then
  23648. X    DEF_AR_FILE=/dev/$dev
  23649. X    break
  23650. X  fi
  23651. Xdone
  23652. Xif test -z "$DEF_AR_FILE"; then
  23653. X  DEF_AR_FILE=-
  23654. Xfi
  23655. X
  23656. Xfor func in strstr valloc mkdir mknod rename ftruncate ftime getcwd
  23657. Xdo
  23658. Xtrfunc=HAVE_`echo $func | tr '[a-z]' '[A-Z]'`
  23659. Xecho checking for ${func}
  23660. Xcat > conftest.c <<EOF
  23661. X#include <stdio.h>
  23662. Xmain() { exit(0); } 
  23663. Xt() { 
  23664. X#ifdef __stub_${func}
  23665. Xchoke me
  23666. X#else
  23667. X/* Override any gcc2 internal prototype to avoid an error.  */
  23668. Xextern char ${func}(); ${func}();
  23669. X#endif
  23670. X }
  23671. XEOF
  23672. Xif eval $compile; then
  23673. X  DEFS="$DEFS -D${trfunc}=1"
  23674. Xfi
  23675. Xrm -f conftest*
  23676. X#endif
  23677. Xdone
  23678. X
  23679. Xecho checking for vprintf
  23680. Xcat > conftest.c <<EOF
  23681. X
  23682. Xmain() { exit(0); } 
  23683. Xt() { vprintf(); }
  23684. XEOF
  23685. Xif eval $compile; then
  23686. X  DEFS="$DEFS -DHAVE_VPRINTF=1"
  23687. Xelse
  23688. X  vprintf_missing=1
  23689. Xfi
  23690. Xrm -f conftest*
  23691. X
  23692. Xif test -n "$vprintf_missing"; then
  23693. Xecho checking for _doprnt
  23694. Xcat > conftest.c <<EOF
  23695. X
  23696. Xmain() { exit(0); } 
  23697. Xt() { _doprnt(); }
  23698. XEOF
  23699. Xif eval $compile; then
  23700. X  DEFS="$DEFS -DHAVE_DOPRNT=1"
  23701. Xfi
  23702. Xrm -f conftest*
  23703. X
  23704. Xfi
  23705. X
  23706. X# The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
  23707. X# for constant arguments.  Useless!
  23708. Xecho checking for working alloca.h
  23709. Xcat > conftest.c <<EOF
  23710. X#include <alloca.h>
  23711. Xmain() { exit(0); } 
  23712. Xt() { char *p = alloca(2 * sizeof(int)); }
  23713. XEOF
  23714. Xif eval $compile; then
  23715. X  DEFS="$DEFS -DHAVE_ALLOCA_H=1"
  23716. Xfi
  23717. Xrm -f conftest*
  23718. X
  23719. Xdecl="#ifdef __GNUC__
  23720. X#define alloca __builtin_alloca
  23721. X#else
  23722. X#if HAVE_ALLOCA_H
  23723. X#include <alloca.h>
  23724. X#else
  23725. X#ifdef _AIX
  23726. X #pragma alloca
  23727. X#else
  23728. Xchar *alloca ();
  23729. X#endif
  23730. X#endif
  23731. X#endif
  23732. X"
  23733. Xecho checking for alloca
  23734. Xcat > conftest.c <<EOF
  23735. X$decl
  23736. Xmain() { exit(0); } 
  23737. Xt() { char *p = (char *) alloca(1); }
  23738. XEOF
  23739. Xif eval $compile; then
  23740. X  :
  23741. Xelse
  23742. X  alloca_missing=1
  23743. Xfi
  23744. Xrm -f conftest*
  23745. X
  23746. Xif test -n "$alloca_missing"; then
  23747. X  # The SVR3 libPW and SVR4 libucb both contain incompatible functions
  23748. X  # that cause trouble.  Some versions do not even contain alloca or
  23749. X  # contain a buggy version.  If you still want to use their alloca,
  23750. X  # use ar to extract alloca.o from them instead of compiling alloca.c.
  23751. X  ALLOCA=alloca.o
  23752. Xfi
  23753. X
  23754. Xecho checking for BSD
  23755. X( test -f /vmunix || test -f /sdmach || test -f /../../mach ) && DEFS="$DEFS -DBSD42=1"
  23756. Xecho checking for HP-UX
  23757. Xtest -f /hp-ux && test ! -f /vmunix && MALLOC=malloc.o
  23758. X
  23759. Xecho checking for Xenix
  23760. Xcat > conftest.c <<EOF
  23761. X#if defined(M_XENIX) && !defined(M_UNIX)
  23762. X  yes
  23763. X#endif
  23764. X
  23765. XEOF
  23766. Xeval "$CPP $DEFS conftest.c > conftest.out 2>&1"
  23767. Xif egrep "yes" conftest.out >/dev/null 2>&1; then
  23768. X  XENIX=1
  23769. Xfi
  23770. Xrm -f conftest*
  23771. X
  23772. Xif test -n "$XENIX"; then
  23773. X  DEFS="$DEFS -DVOID_CLOSEDIR=1"
  23774. X  LIBS="$LIBS -lx"
  23775. X  case "$DEFS" in
  23776. X  *SYSNDIR*) ;;
  23777. X  *) LIBS="-ldir $LIBS" ;; # Make sure -ldir precedes any -lx.
  23778. X  esac
  23779. Xfi
  23780. X
  23781. Xlibname=`echo "socket" | sed 's/lib\([^\.]*\)\.a/\1/;s/-l//'`
  23782. XLIBS_save="${LIBS}"
  23783. XLIBS="${LIBS} -l${libname}"
  23784. Xhave_lib=""
  23785. Xecho checking for -l${libname}
  23786. Xcat > conftest.c <<EOF
  23787. X
  23788. Xmain() { exit(0); } 
  23789. Xt() { main(); }
  23790. XEOF
  23791. Xif eval $compile; then
  23792. X  have_lib="1"
  23793. Xfi
  23794. Xrm -f conftest*
  23795. XLIBS="${LIBS_save}"
  23796. Xif test -n "${have_lib}"; then
  23797. X   :; LIBS="$LIBS -lsocket"
  23798. Xelse
  23799. X   :; 
  23800. Xfi
  23801. X
  23802. Xlibname=`echo "nsl" | sed 's/lib\([^\.]*\)\.a/\1/;s/-l//'`
  23803. XLIBS_save="${LIBS}"
  23804. XLIBS="${LIBS} -l${libname}"
  23805. Xhave_lib=""
  23806. Xecho checking for -l${libname}
  23807. Xcat > conftest.c <<EOF
  23808. X
  23809. Xmain() { exit(0); } 
  23810. Xt() { main(); }
  23811. XEOF
  23812. Xif eval $compile; then
  23813. X  have_lib="1"
  23814. Xfi
  23815. Xrm -f conftest*
  23816. XLIBS="${LIBS_save}"
  23817. Xif test -n "${have_lib}"; then
  23818. X   :; LIBS="$LIBS -lnsl"
  23819. Xelse
  23820. X   :; 
  23821. Xfi
  23822. X
  23823. Xif test -n "$prefix"; then
  23824. X  test -z "$exec_prefix" && exec_prefix='${prefix}'
  23825. X  prsub="s%^prefix\\([     ]*\\)=\\([     ]*\\).*$%prefix\\1=\\2$prefix%"
  23826. Xfi
  23827. Xif test -n "$exec_prefix"; then
  23828. X  prsub="$prsub
  23829. Xs%^exec_prefix\\([     ]*\\)=\\([     ]*\\).*$%\
  23830. Xexec_prefix\\1=\\2$exec_prefix%"
  23831. Xfi
  23832. X
  23833. Xtrap 'rm -f config.status; exit 1' 1 3 15
  23834. Xecho creating config.status
  23835. Xrm -f config.status
  23836. Xcat > config.status <<EOF
  23837. X#!/bin/sh
  23838. X# Generated automatically by configure.
  23839. X# Run this file to recreate the current configuration.
  23840. X# This directory was configured as follows,
  23841. X# on host `(hostname || uname -n) 2>/dev/null`:
  23842. X#
  23843. X# $0 $*
  23844. X
  23845. Xfor arg
  23846. Xdo
  23847. X  case "\$arg" in
  23848. X    -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
  23849. X    exec /bin/sh $0 $* ;;
  23850. X    *) echo "Usage: config.status --recheck" 2>&1; exit 1 ;;
  23851. X  esac
  23852. Xdone
  23853. X
  23854. Xtrap 'rm -f Makefile; exit 1' 1 3 15
  23855. XPROGS='$PROGS'
  23856. XCC='$CC'
  23857. XCPP='$CPP'
  23858. XINSTALL='$INSTALL'
  23859. XINSTALL_PROGRAM='$INSTALL_PROGRAM'
  23860. XINSTALL_DATA='$INSTALL_DATA'
  23861. XYACC='$YACC'
  23862. XRTAPELIB='$RTAPELIB'
  23863. XDEF_AR_FILE='$DEF_AR_FILE'
  23864. XALLOCA='$ALLOCA'
  23865. XMALLOC='$MALLOC'
  23866. XLIBS='$LIBS'
  23867. Xsrcdir='$srcdir'
  23868. XDEFS='$DEFS'
  23869. Xprefix='$prefix'
  23870. Xexec_prefix='$exec_prefix'
  23871. Xprsub='$prsub'
  23872. XEOF
  23873. Xcat >> config.status <<\EOF
  23874. X
  23875. Xtop_srcdir=$srcdir
  23876. Xfor file in .. Makefile; do if [ "x$file" != "x.." ]; then
  23877. X  srcdir=$top_srcdir
  23878. X  # Remove last slash and all that follows it.  Not all systems have dirname.
  23879. X  dir=`echo $file|sed 's%/[^/][^/]*$%%'`
  23880. X  if test "$dir" != "$file"; then
  23881. X    test "$top_srcdir" != . && srcdir=$top_srcdir/$dir
  23882. X    test ! -d $dir && mkdir $dir
  23883. X  fi
  23884. X  echo creating $file
  23885. X  rm -f $file
  23886. X  echo "# Generated automatically from `echo $file|sed 's|.*/||'`.in by configure." > $file
  23887. X  sed -e "
  23888. X$prsub
  23889. Xs%@PROGS@%$PROGS%g
  23890. Xs%@CC@%$CC%g
  23891. Xs%@CPP@%$CPP%g
  23892. Xs%@INSTALL@%$INSTALL%g
  23893. Xs%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
  23894. Xs%@INSTALL_DATA@%$INSTALL_DATA%g
  23895. Xs%@YACC@%$YACC%g
  23896. Xs%@RTAPELIB@%$RTAPELIB%g
  23897. Xs%@DEF_AR_FILE@%$DEF_AR_FILE%g
  23898. Xs%@ALLOCA@%$ALLOCA%g
  23899. Xs%@MALLOC@%$MALLOC%g
  23900. Xs%@LIBS@%$LIBS%g
  23901. Xs%@srcdir@%$srcdir%g
  23902. Xs%@DEFS@%$DEFS%
  23903. X" $top_srcdir/${file}.in >> $file
  23904. Xfi; done
  23905. X
  23906. Xexit 0
  23907. XEOF
  23908. Xchmod +x config.status
  23909. Xtest -n "$no_create" || ./config.status
  23910. X
  23911. END_OF_FILE
  23912. if test 19657 -ne `wc -c <'configure'`; then
  23913.     echo shar: \"'configure'\" unpacked with wrong size!
  23914. fi
  23915. chmod +x 'configure'
  23916. # end of 'configure'
  23917. fi
  23918. if test -f 'configure.in' -a "${1}" != "-c" ; then 
  23919.   echo shar: Will not clobber existing file \"'configure.in'\"
  23920. else
  23921. echo shar: Extracting \"'configure.in'\" \(1551 characters\)
  23922. sed "s/^X//" >'configure.in' <<'END_OF_FILE'
  23923. Xdnl Process this file with autoconf to produce a configure script.
  23924. XAC_INIT(tar.h)
  23925. XPROGS="tar"
  23926. XAC_SUBST(PROGS)dnl
  23927. XAC_PROG_CC
  23928. XAC_PROG_CPP
  23929. XAC_GCC_TRADITIONAL
  23930. XAC_PROG_INSTALL
  23931. XAC_PROG_YACC
  23932. XAC_AIX
  23933. XAC_MINIX
  23934. XAC_ISC_POSIX
  23935. XAC_RETSIGTYPE
  23936. XAC_SIZE_T
  23937. XAC_MAJOR_HEADER
  23938. XAC_DIR_HEADER
  23939. X# The 3-argument open happens to go along with the O_* defines,
  23940. X# which are easier to check for.
  23941. XAC_HEADER_CHECK(fcntl.h, open_header=fcntl.h, open_header=sys/file.h)
  23942. XAC_COMPILE_CHECK(3-argument open,
  23943. X[#include <$open_header>], [int x = O_RDONLY;], , AC_DEFINE(EMUL_OPEN3))
  23944. XAC_REMOTE_TAPE
  23945. XAC_RSH
  23946. XAC_STDC_HEADERS
  23947. XAC_UNISTD_H
  23948. Xecho checking for getgrgid declaration
  23949. XAC_HEADER_EGREP(getgrgid, grp.h, AC_DEFINE(HAVE_GETGRGID))
  23950. Xecho checking for getpwuid declaration
  23951. XAC_HEADER_EGREP(getpwuid, pwd.h, AC_DEFINE(HAVE_GETPWUID))
  23952. XAC_HAVE_HEADERS(string.h limits.h)
  23953. Xecho checking default archive
  23954. X# This might guess wrong, but it's not very important.
  23955. Xfor dev in rmt8 rmt0 rmt0h rct0 rst0 tape rct/c7d0s2
  23956. Xdo
  23957. X  if test -n "`ls /dev/$dev 2>/dev/null`"; then
  23958. X    DEF_AR_FILE=/dev/$dev
  23959. X    break
  23960. X  fi
  23961. Xdone
  23962. Xif test -z "$DEF_AR_FILE"; then
  23963. X  DEF_AR_FILE=-
  23964. Xfi
  23965. X
  23966. XAC_SUBST(DEF_AR_FILE)dnl
  23967. XAC_HAVE_FUNCS(strstr valloc mkdir mknod rename ftruncate ftime getcwd)
  23968. XAC_VPRINTF
  23969. XAC_ALLOCA
  23970. Xecho checking for BSD
  23971. X( test -f /vmunix || test -f /sdmach || test -f /../../mach ) && AC_DEFINE(BSD42)
  23972. Xecho checking for HP-UX
  23973. Xtest -f /hp-ux && test ! -f /vmunix && MALLOC=malloc.o
  23974. XAC_SUBST(MALLOC)
  23975. XAC_XENIX_DIR
  23976. XAC_HAVE_LIBRARY(socket, [LIBS="$LIBS -lsocket"])
  23977. XAC_HAVE_LIBRARY(nsl, [LIBS="$LIBS -lnsl"])
  23978. XAC_OUTPUT(Makefile)
  23979. END_OF_FILE
  23980. if test 1551 -ne `wc -c <'configure.in'`; then
  23981.     echo shar: \"'configure.in'\" unpacked with wrong size!
  23982. fi
  23983. # end of 'configure.in'
  23984. fi
  23985. if test -f 'tar.h' -a "${1}" != "-c" ; then 
  23986.   echo shar: Will not clobber existing file \"'tar.h'\"
  23987. else
  23988. echo shar: Extracting \"'tar.h'\" \(9318 characters\)
  23989. sed "s/^X//" >'tar.h' <<'END_OF_FILE'
  23990. X/* Declarations for tar archives.
  23991. X   Copyright (C) 1988, 1992, 1993 Free Software Foundation
  23992. X
  23993. XThis file is part of GNU Tar.
  23994. X
  23995. XGNU Tar is free software; you can redistribute it and/or modify
  23996. Xit under the terms of the GNU General Public License as published by
  23997. Xthe Free Software Foundation; either version 2, or (at your option)
  23998. Xany later version.
  23999. X
  24000. XGNU Tar is distributed in the hope that it will be useful,
  24001. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  24002. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24003. XGNU General Public License for more details.
  24004. X
  24005. XYou should have received a copy of the GNU General Public License
  24006. Xalong with GNU Tar; see the file COPYING.  If not, write to
  24007. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24008. X
  24009. X#include "testpad.h"
  24010. X
  24011. X/* major() and minor() macros (among other things) defined here for hpux */
  24012. X#ifdef hpux
  24013. X#include <sys/mknod.h>
  24014. X#endif
  24015. X
  24016. X/*
  24017. X * Kludge for handling systems that can't cope with multiple
  24018. X * external definitions of a variable.  In ONE routine (tar.c),
  24019. X * we #define TAR_EXTERN to null; here, we set it to "extern" if
  24020. X * it is not already set.
  24021. X */
  24022. X#ifndef TAR_EXTERN
  24023. X#define TAR_EXTERN extern
  24024. X#endif
  24025. X
  24026. X/*
  24027. X * Header block on tape.
  24028. X *
  24029. X * I'm going to use traditional DP naming conventions here.
  24030. X * A "block" is a big chunk of stuff that we do I/O on.
  24031. X * A "record" is a piece of info that we care about.
  24032. X * Typically many "record"s fit into a "block".
  24033. X */
  24034. X#define    RECORDSIZE    512
  24035. X#define    NAMSIZ        100
  24036. X#define    TUNMLEN        32
  24037. X#define    TGNMLEN        32
  24038. X#define SPARSE_EXT_HDR  21
  24039. X#define SPARSE_IN_HDR    4
  24040. X
  24041. Xstruct sparse
  24042. X  {
  24043. X    char offset[12];
  24044. X    char numbytes[12];
  24045. X  };
  24046. X
  24047. Xstruct sp_array
  24048. X  {
  24049. X    int offset;
  24050. X    int numbytes;
  24051. X  };
  24052. X
  24053. Xunion record
  24054. X  {
  24055. X    char charptr[RECORDSIZE];
  24056. X    struct header
  24057. X      {
  24058. X    char arch_name[NAMSIZ];
  24059. X    char mode[8];
  24060. X    char uid[8];
  24061. X    char gid[8];
  24062. X    char size[12];
  24063. X    char mtime[12];
  24064. X    char chksum[8];
  24065. X    char linkflag;
  24066. X    char arch_linkname[NAMSIZ];
  24067. X    char magic[8];
  24068. X    char uname[TUNMLEN];
  24069. X    char gname[TGNMLEN];
  24070. X    char devmajor[8];
  24071. X    char devminor[8];
  24072. X    /* these following fields were added by JF for gnu */
  24073. X    /* and are NOT standard */
  24074. X    char atime[12];
  24075. X    char ctime[12];
  24076. X    char offset[12];
  24077. X    char longnames[4];
  24078. X#ifdef NEEDPAD
  24079. X    char pad;
  24080. X#endif
  24081. X    struct sparse sp[SPARSE_IN_HDR];
  24082. X    char isextended;
  24083. X    char realsize[12];    /* true size of the sparse file */
  24084. X    /* char    ending_blanks[12];*//* number of nulls at the
  24085. X       end of the file, if any */
  24086. X      }
  24087. X    header;
  24088. X    struct extended_header
  24089. X      {
  24090. X    struct sparse sp[21];
  24091. X    char isextended;
  24092. X      }
  24093. X    ext_hdr;
  24094. X  };
  24095. X
  24096. X/* The checksum field is filled with this while the checksum is computed. */
  24097. X#define    CHKBLANKS    "        "    /* 8 blanks, no null */
  24098. X
  24099. X/* The magic field is filled with this if uname and gname are valid. */
  24100. X#define    TMAGIC        "ustar  "    /* 7 chars and a null */
  24101. X
  24102. X/* The linkflag defines the type of file */
  24103. X#define    LF_OLDNORMAL    '\0'    /* Normal disk file, Unix compat */
  24104. X#define    LF_NORMAL    '0'    /* Normal disk file */
  24105. X#define    LF_LINK        '1'    /* Link to previously dumped file */
  24106. X#define    LF_SYMLINK    '2'    /* Symbolic link */
  24107. X#define    LF_CHR        '3'    /* Character special file */
  24108. X#define    LF_BLK        '4'    /* Block special file */
  24109. X#define    LF_DIR        '5'    /* Directory */
  24110. X#define    LF_FIFO        '6'    /* FIFO special file */
  24111. X#define    LF_CONTIG    '7'    /* Contiguous file */
  24112. X/* Further link types may be defined later. */
  24113. X
  24114. X/* Note that the standards committee allows only capital A through
  24115. X   capital Z for user-defined expansion.  This means that defining something
  24116. X   as, say '8' is a *bad* idea. */
  24117. X#define LF_DUMPDIR    'D'    /* This is a dir entry that contains
  24118. X                       the names of files that were in
  24119. X                       the dir at the time the dump
  24120. X                       was made */
  24121. X#define LF_LONGLINK    'K'    /* Identifies the NEXT file on the tape
  24122. X                       as having a long linkname */
  24123. X#define LF_LONGNAME    'L'    /* Identifies the NEXT file on the tape
  24124. X                       as having a long name. */
  24125. X#define LF_MULTIVOL    'M'    /* This is the continuation
  24126. X                       of a file that began on another
  24127. X                       volume */
  24128. X#define LF_NAMES    'N'    /* For storing filenames that didn't
  24129. X                       fit in 100 characters */
  24130. X#define LF_SPARSE    'S'    /* This is for sparse files */
  24131. X#define LF_VOLHDR    'V'    /* This file is a tape/volume header */
  24132. X/* Ignore it on extraction */
  24133. X
  24134. X/*
  24135. X * Exit codes from the "tar" program
  24136. X */
  24137. X#define    EX_SUCCESS    0    /* success! */
  24138. X#define    EX_ARGSBAD    1    /* invalid args */
  24139. X#define    EX_BADFILE    2    /* invalid filename */
  24140. X#define    EX_BADARCH    3    /* bad archive */
  24141. X#define    EX_SYSTEM    4    /* system gave unexpected error */
  24142. X#define EX_BADVOL    5    /* Special error code means
  24143. X                   Tape volume doesn't match the one
  24144. X                   specified on the command line */
  24145. X
  24146. X/*
  24147. X * Global variables
  24148. X */
  24149. XTAR_EXTERN union record *ar_block;    /* Start of block of archive */
  24150. XTAR_EXTERN union record *ar_record;    /* Current record of archive */
  24151. XTAR_EXTERN union record *ar_last;    /* Last+1 record of archive block */
  24152. XTAR_EXTERN char ar_reading;    /* 0 writing, !0 reading archive */
  24153. XTAR_EXTERN int blocking;    /* Size of each block, in records */
  24154. XTAR_EXTERN int blocksize;    /* Size of each block, in bytes */
  24155. XTAR_EXTERN char *info_script;    /* Script to run at end of each tape change */
  24156. XTAR_EXTERN char *name_file;    /* File containing names to work on */
  24157. XTAR_EXTERN char filename_terminator;    /* \n or \0. */
  24158. XTAR_EXTERN char *tar;        /* Name of this program */
  24159. XTAR_EXTERN struct sp_array *sparsearray;    /* Pointer to the start of the scratch space */
  24160. XTAR_EXTERN int sp_array_size;    /* Initial size of the sparsearray */
  24161. XTAR_EXTERN int tot_written;    /* Total written to output */
  24162. XTAR_EXTERN struct re_pattern_buffer
  24163. X *label_pattern;        /* compiled regex for extract label */
  24164. XTAR_EXTERN char **ar_files;    /* list of tape drive names */
  24165. XTAR_EXTERN int n_ar_files;    /* number of tape drive names */
  24166. XTAR_EXTERN int cur_ar_file;    /* tape drive currently being used */
  24167. XTAR_EXTERN int ar_files_len;    /* malloced size of ar_files */
  24168. XTAR_EXTERN char *current_file_name, *current_link_name;
  24169. X
  24170. X/*
  24171. X * Flags from the command line
  24172. X */
  24173. XTAR_EXTERN int cmd_mode;
  24174. X#define CMD_NONE    0
  24175. X#define CMD_CAT        1    /* -A */
  24176. X#define CMD_CREATE    2    /* -c */
  24177. X#define CMD_DIFF    3    /* -d */
  24178. X#define CMD_APPEND    4    /* -r */
  24179. X#define CMD_LIST    5    /* -t */
  24180. X#define CMD_UPDATE    6    /* -u */
  24181. X#define CMD_EXTRACT    7    /* -x */
  24182. X#define CMD_DELETE    8    /* -D */
  24183. X#define CMD_VERSION    9    /* --version */
  24184. X
  24185. X
  24186. XTAR_EXTERN int f_reblock;    /* -B */
  24187. X#if 0
  24188. XTAR_EXTERN char f_dironly;    /* -D */
  24189. X#endif
  24190. XTAR_EXTERN int f_run_script_at_end;    /* -F */
  24191. XTAR_EXTERN int f_gnudump;    /* -G */
  24192. XTAR_EXTERN int f_follow_links;    /* -h */
  24193. XTAR_EXTERN int f_ignorez;    /* -i */
  24194. XTAR_EXTERN int f_keep;        /* -k */
  24195. XTAR_EXTERN int f_startfile;    /* -K */
  24196. XTAR_EXTERN int f_local_filesys;    /* -l */
  24197. XTAR_EXTERN int tape_length;    /* -L */
  24198. XTAR_EXTERN int f_modified;    /* -m */
  24199. XTAR_EXTERN int f_multivol;    /* -M */
  24200. XTAR_EXTERN int f_new_files;    /* -N */
  24201. XTAR_EXTERN int f_oldarch;    /* -o */
  24202. XTAR_EXTERN int f_exstdout;    /* -O */
  24203. XTAR_EXTERN int f_use_protection;/* -p */
  24204. XTAR_EXTERN int f_absolute_paths;/* -P */
  24205. XTAR_EXTERN int f_sayblock;    /* -R */
  24206. XTAR_EXTERN int f_sorted_names;    /* -s */
  24207. XTAR_EXTERN int f_sparse_files;    /* -S  ... JK */
  24208. XTAR_EXTERN int f_namefile;    /* -T */
  24209. XTAR_EXTERN int f_verbose;    /* -v */
  24210. XTAR_EXTERN char *f_volhdr;    /* -V */
  24211. XTAR_EXTERN int f_confirm;    /* -w */
  24212. XTAR_EXTERN int f_verify;    /* -W */
  24213. XTAR_EXTERN int f_exclude;    /* -X */
  24214. XTAR_EXTERN char *f_compressprog;    /* -z and -Z */
  24215. XTAR_EXTERN int f_do_chown;    /* --do-chown */
  24216. XTAR_EXTERN int f_totals;    /* --totals */
  24217. XTAR_EXTERN int f_remove_files;    /* --remove-files */
  24218. XTAR_EXTERN int f_ignore_failed_read;    /* --ignore-failed-read */
  24219. XTAR_EXTERN int f_checkpoint;    /* --checkpoint */
  24220. XTAR_EXTERN int f_show_omitted_dirs;    /* --show-omitted-dirs */
  24221. XTAR_EXTERN char *f_volno_file;    /* --volno-file */
  24222. XTAR_EXTERN int f_force_local;    /* --force-local */
  24223. XTAR_EXTERN int f_atime_preserve;/* --atime-preserve */
  24224. XTAR_EXTERN int f_compress_block; /* --compress-block */
  24225. X
  24226. X/*
  24227. X * We default to Unix Standard format rather than 4.2BSD tar format.
  24228. X * The code can actually produce all three:
  24229. X *    f_standard    ANSI standard
  24230. X *    f_oldarch    V7
  24231. X *    neither        4.2BSD
  24232. X * but we don't bother, since 4.2BSD can read ANSI standard format anyway.
  24233. X * The only advantage to the "neither" option is that we can cmp our
  24234. X * output to the output of 4.2BSD tar, for debugging.
  24235. X */
  24236. X#define        f_standard        (!f_oldarch)
  24237. X
  24238. X/*
  24239. X * Structure for keeping track of filenames and lists thereof.
  24240. X */
  24241. Xstruct name
  24242. X  {
  24243. X    struct name *next;
  24244. X    short length;        /* cached strlen(name) */
  24245. X    char found;            /* A matching file has been found */
  24246. X    char firstch;        /* First char is literally matched */
  24247. X    char regexp;        /* This name is a regexp, not literal */
  24248. X    char *change_dir;        /* JF set with the -C option */
  24249. X    char *dir_contents;        /* JF for f_gnudump */
  24250. X    char fake;            /* dummy entry */
  24251. X    char name[1];
  24252. X  };
  24253. X
  24254. XTAR_EXTERN struct name *namelist;    /* Points to first name in list */
  24255. XTAR_EXTERN struct name *namelast;    /* Points to last name in list */
  24256. X
  24257. XTAR_EXTERN int archive;        /* File descriptor for archive file */
  24258. XTAR_EXTERN int errors;        /* # of files in error */
  24259. X
  24260. XTAR_EXTERN char *gnu_dumpfile;
  24261. X
  24262. X/*
  24263. X * Error recovery stuff
  24264. X */
  24265. XTAR_EXTERN char read_error_flag;
  24266. X
  24267. X
  24268. X/*
  24269. X * Declarations of functions available to the world.
  24270. X */
  24271. Xunion record *findrec ();
  24272. Xvoid userec ();
  24273. Xunion record *endofrecs ();
  24274. Xvoid anno ();
  24275. X
  24276. X#if defined (HAVE_VPRINTF) && __STDC__
  24277. Xvoid msg (char *,...);
  24278. Xvoid msg_perror (char *,...);
  24279. X#else
  24280. Xvoid msg ();
  24281. Xvoid msg_perror ();
  24282. X#endif
  24283. END_OF_FILE
  24284. if test 9318 -ne `wc -c <'tar.h'`; then
  24285.     echo shar: \"'tar.h'\" unpacked with wrong size!
  24286. fi
  24287. # end of 'tar.h'
  24288. fi
  24289. if test -f 'fnmatch.h' -a "${1}" != "-c" ; then 
  24290.   echo shar: Will not clobber existing file \"'fnmatch.h'\"
  24291. else
  24292. echo shar: Extracting \"'fnmatch.h'\" \(1955 characters\)
  24293. sed "s/^X//" >'fnmatch.h' <<'END_OF_FILE'
  24294. X/* Copyright (C) 1991, 1992 Free Software Foundation, Inc.
  24295. X
  24296. XThis library is free software; you can redistribute it and/or
  24297. Xmodify it under the terms of the GNU Library General Public License as
  24298. Xpublished by the Free Software Foundation; either version 2 of the
  24299. XLicense, or (at your option) any later version.
  24300. X
  24301. XThis library is distributed in the hope that it will be useful,
  24302. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  24303. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  24304. XLibrary General Public License for more details.
  24305. X
  24306. XYou should have received a copy of the GNU Library General Public
  24307. XLicense along with this library; see the file COPYING.LIB.  If
  24308. Xnot, write to the Free Software Foundation, Inc., 675 Mass Ave,
  24309. XCambridge, MA 02139, USA.  */
  24310. X
  24311. X#ifndef    _FNMATCH_H
  24312. X
  24313. X#define    _FNMATCH_H    1
  24314. X
  24315. X#ifdef    __cplusplus
  24316. Xextern "C" {
  24317. X#endif
  24318. X
  24319. X#if defined (__cplusplus) || (defined (__STDC__) && __STDC__)
  24320. X#undef    __P
  24321. X#define    __P(args)    args
  24322. X#else /* Not C++ or ANSI C.  */
  24323. X#undef    __P
  24324. X#define    __P(args)    ()
  24325. X#undef    const
  24326. X#define    const
  24327. X#endif /* C++ or ANSI C.  */
  24328. X
  24329. X/* Bits set in the FLAGS argument to `fnmatch'.  */
  24330. X#define    FNM_PATHNAME    (1 << 0)/* No wildcard can ever match `/'.  */
  24331. X#define    FNM_NOESCAPE    (1 << 1)/* Backslashes don't quote special chars.  */
  24332. X#define    FNM_PERIOD    (1 << 2)/* Leading `.' is matched only explicitly.  */
  24333. X#define    __FNM_FLAGS    (FNM_PATHNAME|FNM_NOESCAPE|FNM_PERIOD|FNM_LEADING_DIR)
  24334. X
  24335. X#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_BSD_SOURCE)
  24336. X#define    FNM_LEADING_DIR    (1 << 3)/* Ignore `/...' after a match.  */
  24337. X#define    FNM_FILE_NAME    FNM_PATHNAME
  24338. X#endif
  24339. X
  24340. X/* Value returned by `fnmatch' if STRING does not match PATTERN.  */
  24341. X#define    FNM_NOMATCH    1
  24342. X
  24343. X/* Match STRING against the filename pattern PATTERN,
  24344. X   returning zero if it matches, FNM_NOMATCH if not.  */
  24345. Xextern int fnmatch __P ((const char *__pattern, const char *__string,
  24346. X             int __flags));
  24347. X
  24348. X#ifdef    __cplusplus
  24349. X}
  24350. X#endif
  24351. X
  24352. X#endif /* fnmatch.h */
  24353. END_OF_FILE
  24354. if test 1955 -ne `wc -c <'fnmatch.h'`; then
  24355.     echo shar: \"'fnmatch.h'\" unpacked with wrong size!
  24356. fi
  24357. # end of 'fnmatch.h'
  24358. fi
  24359. if test -f 'pathmax.h' -a "${1}" != "-c" ; then 
  24360.   echo shar: Will not clobber existing file \"'pathmax.h'\"
  24361. else
  24362. echo shar: Extracting \"'pathmax.h'\" \(1691 characters\)
  24363. sed "s/^X//" >'pathmax.h' <<'END_OF_FILE'
  24364. X/* Define PATH_MAX somehow.  Requires sys/types.h.
  24365. X   Copyright (C) 1992 Free Software Foundation, Inc.
  24366. X
  24367. X   This program is free software; you can redistribute it and/or modify
  24368. X   it under the terms of the GNU General Public License as published by
  24369. X   the Free Software Foundation; either version 2, or (at your option)
  24370. X   any later version.
  24371. X
  24372. X   This program is distributed in the hope that it will be useful,
  24373. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  24374. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24375. X   GNU General Public License for more details.
  24376. X
  24377. X   You should have received a copy of the GNU General Public License
  24378. X   along with this program; if not, write to the Free Software
  24379. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24380. X
  24381. X#ifndef _PATHMAX_H
  24382. X#define _PATHMAX_H
  24383. X
  24384. X#ifdef HAVE_UNISTD_H
  24385. X#include <unistd.h>
  24386. X#endif
  24387. X
  24388. X/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
  24389. X   PATH_MAX but might cause redefinition warnings when sys/param.h is
  24390. X   later included (as on MORE/BSD 4.3).  */
  24391. X#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && defined(USG))
  24392. X#include <limits.h>
  24393. X#endif
  24394. X
  24395. X#ifndef _POSIX_PATH_MAX
  24396. X#define _POSIX_PATH_MAX 255
  24397. X#endif
  24398. X
  24399. X#if !defined(PATH_MAX) && defined(_PC_PATH_MAX)
  24400. X#define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
  24401. X#endif
  24402. X
  24403. X/* Don't include sys/param.h if it already has been.  */
  24404. X#if !defined(PATH_MAX) && !defined(MAXPATHLEN) && !defined(__MSDOS__)
  24405. X#include <sys/param.h>
  24406. X#endif
  24407. X
  24408. X#if !defined(PATH_MAX) && defined(MAXPATHLEN)
  24409. X#define PATH_MAX MAXPATHLEN
  24410. X#endif
  24411. X
  24412. X#ifndef PATH_MAX
  24413. X#define PATH_MAX _POSIX_PATH_MAX
  24414. X#endif
  24415. X
  24416. X#endif /* _PATHMAX_H */
  24417. END_OF_FILE
  24418. if test 1691 -ne `wc -c <'pathmax.h'`; then
  24419.     echo shar: \"'pathmax.h'\" unpacked with wrong size!
  24420. fi
  24421. # end of 'pathmax.h'
  24422. fi
  24423. if test -f 'port.h' -a "${1}" != "-c" ; then 
  24424.   echo shar: Will not clobber existing file \"'port.h'\"
  24425. else
  24426. echo shar: Extracting \"'port.h'\" \(5312 characters\)
  24427. sed "s/^X//" >'port.h' <<'END_OF_FILE'
  24428. X/* Portability declarations.  Requires sys/types.h.
  24429. X   Copyright (C) 1988, 1992 Free Software Foundation
  24430. X
  24431. XThis file is part of GNU Tar.
  24432. X
  24433. XGNU Tar is free software; you can redistribute it and/or modify
  24434. Xit under the terms of the GNU General Public License as published by
  24435. Xthe Free Software Foundation; either version 2, or (at your option)
  24436. Xany later version.
  24437. X
  24438. XGNU Tar is distributed in the hope that it will be useful,
  24439. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  24440. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24441. XGNU General Public License for more details.
  24442. X
  24443. XYou should have received a copy of the GNU General Public License
  24444. Xalong with GNU Tar; see the file COPYING.  If not, write to
  24445. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24446. X
  24447. X/* AIX requires this to be the first thing in the file. */
  24448. X#ifdef __GNUC__
  24449. X#define alloca __builtin_alloca
  24450. X#else /* not __GNUC__ */
  24451. X#if HAVE_ALLOCA_H
  24452. X#include <alloca.h>
  24453. X#else /* not HAVE_ALLOCA_H */
  24454. X#ifdef _AIX
  24455. X #pragma alloca
  24456. X#else /* not _AIX */
  24457. Xchar *alloca ();
  24458. X#endif /* not _AIX */
  24459. X#endif /* not HAVE_ALLOCA_H */
  24460. X#endif /* not __GNUC__ */
  24461. X
  24462. X#include "pathmax.h"
  24463. X
  24464. X#ifdef _POSIX_VERSION
  24465. X#include <sys/wait.h>
  24466. X#else /* !_POSIX_VERSION */
  24467. X#define WIFSTOPPED(w) (((w) & 0xff) == 0x7f)
  24468. X#define WIFSIGNALED(w) (((w) & 0xff) != 0x7f && ((w) & 0xff) != 0)
  24469. X#define WIFEXITED(w) (((w) & 0xff) == 0)
  24470. X
  24471. X#define WSTOPSIG(w) (((w) >> 8) & 0xff)
  24472. X#define WTERMSIG(w) ((w) & 0x7f)
  24473. X#define WEXITSTATUS(w) (((w) >> 8) & 0xff)
  24474. X#endif /* _POSIX_VERSION */
  24475. X
  24476. X/* nonstandard */
  24477. X#ifndef WIFCOREDUMPED
  24478. X#define WIFCOREDUMPED(w) (((w) & 0x80) != 0)
  24479. X#endif
  24480. X
  24481. X#ifdef __MSDOS__
  24482. X/* missing things from sys/stat.h */
  24483. X#define    S_ISUID        0
  24484. X#define    S_ISGID        0
  24485. X#define    S_ISVTX        0
  24486. X
  24487. X/* device stuff */
  24488. X#define    makedev(ma, mi)        ((ma << 8) | mi)
  24489. X#define    major(dev)        (dev)
  24490. X#define    minor(dev)        (dev)
  24491. Xtypedef long off_t;
  24492. X#endif /* __MSDOS__ */
  24493. X
  24494. X#if defined(__STDC__) || defined(__TURBOC__)
  24495. X#define PTR void *
  24496. X#else
  24497. X#define PTR char *
  24498. X#define const
  24499. X#endif
  24500. X
  24501. X/* Since major is a function on SVR4, we can't just use `ifndef major'.  */
  24502. X#ifdef major            /* Might be defined in sys/types.h.  */
  24503. X#define HAVE_MAJOR
  24504. X#endif
  24505. X
  24506. X#if !defined(HAVE_MAJOR) && defined(MAJOR_IN_MKDEV)
  24507. X#include <sys/mkdev.h>
  24508. X#define HAVE_MAJOR
  24509. X#endif
  24510. X
  24511. X#if !defined(HAVE_MAJOR) && defined(MAJOR_IN_SYSMACROS)
  24512. X#include <sys/sysmacros.h>
  24513. X#define HAVE_MAJOR
  24514. X#endif
  24515. X
  24516. X#ifndef HAVE_MAJOR
  24517. X#define major(dev)  (((dev) >> 8) & 0xff)
  24518. X#define minor(dev)  ((dev) & 0xff)
  24519. X#define makedev(maj, min)  (((maj) << 8) | (min))
  24520. X#endif
  24521. X#undef HAVE_MAJOR
  24522. X
  24523. X#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
  24524. X#include <string.h>
  24525. X#if !defined(__MSDOS__) && !defined(STDC_HEADERS)
  24526. X#include <memory.h>
  24527. X#endif
  24528. X#ifdef index
  24529. X#undef index
  24530. X#endif
  24531. X#ifdef rindex
  24532. X#undef rindex
  24533. X#endif
  24534. X#define index strchr
  24535. X#define rindex strrchr
  24536. X#define bcopy(s, d, n) memcpy(d, s, n)
  24537. X#define bzero(s, n) memset(s, 0, n)
  24538. X#define bcmp memcmp
  24539. X#else
  24540. X#include <strings.h>
  24541. X#endif
  24542. X
  24543. X#if defined(STDC_HEADERS)
  24544. X#include <stdlib.h>
  24545. X#else
  24546. Xchar *malloc (), *realloc ();
  24547. Xchar *getenv ();
  24548. X#endif
  24549. X
  24550. X#ifndef _POSIX_VERSION
  24551. X#ifdef __MSDOS__
  24552. X#include <io.h>
  24553. X#else /* !__MSDOS__ */
  24554. Xoff_t lseek ();
  24555. X#endif /* !__MSDOS__ */
  24556. Xchar *getcwd ();
  24557. X#endif /* !_POSIX_VERSION */
  24558. X
  24559. X#ifndef NULL
  24560. X#define NULL 0
  24561. X#endif
  24562. X
  24563. X#ifndef    O_BINARY
  24564. X#define    O_BINARY    0
  24565. X#endif
  24566. X#ifndef O_CREAT
  24567. X#define O_CREAT        0
  24568. X#endif
  24569. X#ifndef    O_NDELAY
  24570. X#define    O_NDELAY    0
  24571. X#endif
  24572. X#ifndef    O_RDONLY
  24573. X#define    O_RDONLY    0
  24574. X#endif
  24575. X#ifndef O_RDWR
  24576. X#define O_RDWR        2
  24577. X#endif
  24578. X
  24579. X#include <sys/stat.h>
  24580. X#ifndef S_ISREG            /* Doesn't have POSIX.1 stat stuff. */
  24581. X#define mode_t unsigned short
  24582. X#endif
  24583. X#if !defined(S_ISBLK) && defined(S_IFBLK)
  24584. X#define    S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
  24585. X#endif
  24586. X#if !defined(S_ISCHR) && defined(S_IFCHR)
  24587. X#define    S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
  24588. X#endif
  24589. X#if !defined(S_ISDIR) && defined(S_IFDIR)
  24590. X#define    S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
  24591. X#endif
  24592. X#if !defined(S_ISREG) && defined(S_IFREG)
  24593. X#define    S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
  24594. X#endif
  24595. X#if !defined(S_ISFIFO) && defined(S_IFIFO)
  24596. X#define    S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
  24597. X#define mkfifo(path, mode) (mknod ((path), (mode) | S_IFIFO, 0))
  24598. X#endif
  24599. X#if !defined(S_ISLNK) && defined(S_IFLNK)
  24600. X#define    S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
  24601. X#endif
  24602. X#if !defined(S_ISSOCK) && defined(S_IFSOCK)
  24603. X#define    S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
  24604. X#endif
  24605. X#if !defined(S_ISMPB) && defined(S_IFMPB)    /* V7 */
  24606. X#define S_ISMPB(m) (((m) & S_IFMT) == S_IFMPB)
  24607. X#define S_ISMPC(m) (((m) & S_IFMT) == S_IFMPC)
  24608. X#endif
  24609. X#if !defined(S_ISNWK) && defined(S_IFNWK)    /* HP/UX */
  24610. X#define S_ISNWK(m) (((m) & S_IFMT) == S_IFNWK)
  24611. X#endif
  24612. X#if !defined(S_ISCTG) && defined(S_IFCTG)    /* contiguous file */
  24613. X#define S_ISCTG(m) (((m) & S_IFMT) == S_IFCTG)
  24614. X#endif
  24615. X#if !defined(S_ISVTX)
  24616. X#define S_ISVTX 0001000
  24617. X#endif
  24618. X
  24619. X#ifdef __MSDOS__
  24620. X#include "msd_dir.h"
  24621. X#define NLENGTH(direct) ((direct)->d_namlen)
  24622. X
  24623. X#else /* not __MSDOS__ */
  24624. X
  24625. X#if defined(DIRENT) || defined(_POSIX_VERSION)
  24626. X#include <dirent.h>
  24627. X#define NLENGTH(direct) (strlen((direct)->d_name))
  24628. X#else /* not (DIRENT or _POSIX_VERSION) */
  24629. X#define dirent direct
  24630. X#define NLENGTH(direct) ((direct)->d_namlen)
  24631. X#ifdef SYSNDIR
  24632. X#include <sys/ndir.h>
  24633. X#endif /* SYSNDIR */
  24634. X#ifdef SYSDIR
  24635. X#include <sys/dir.h>
  24636. X#endif /* SYSDIR */
  24637. X#ifdef NDIR
  24638. X#include <ndir.h>
  24639. X#endif /* NDIR */
  24640. X#endif /* DIRENT or _POSIX_VERSION */
  24641. X
  24642. X#endif /* not __MSDOS__ */
  24643. END_OF_FILE
  24644. if test 5312 -ne `wc -c <'port.h'`; then
  24645.     echo shar: \"'port.h'\" unpacked with wrong size!
  24646. fi
  24647. # end of 'port.h'
  24648. fi
  24649. if test -f 'open3.h' -a "${1}" != "-c" ; then 
  24650.   echo shar: Will not clobber existing file \"'open3.h'\"
  24651. else
  24652. echo shar: Extracting \"'open3.h'\" \(2639 characters\)
  24653. sed "s/^X//" >'open3.h' <<'END_OF_FILE'
  24654. X/* Defines for Sys V style 3-argument open call.
  24655. X   Copyright (C) 1988 Free Software Foundation
  24656. X
  24657. XThis file is part of GNU Tar.
  24658. X
  24659. XGNU Tar is free software; you can redistribute it and/or modify
  24660. Xit under the terms of the GNU General Public License as published by
  24661. Xthe Free Software Foundation; either version 2, or (at your option)
  24662. Xany later version.
  24663. X
  24664. XGNU Tar is distributed in the hope that it will be useful,
  24665. Xbut WITHOUT ANY WARRANTY; without even the implied warranty of
  24666. XMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24667. XGNU General Public License for more details.
  24668. X
  24669. XYou should have received a copy of the GNU General Public License
  24670. Xalong with GNU Tar; see the file COPYING.  If not, write to
  24671. Xthe Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24672. X
  24673. X/*
  24674. X * open3.h -- #defines for the various flags for the Sys V style 3-argument
  24675. X * open() call.  On BSD or System 5, the system already has this in an
  24676. X * include file.  This file is needed for V7 and MINIX systems for the
  24677. X * benefit of open3() in port.c, a routine that emulates the 3-argument
  24678. X * call using system calls available on V7/MINIX.
  24679. X *
  24680. X * This file is needed by PD tar even if we aren't using the
  24681. X * emulator, since the #defines for O_WRONLY, etc. are used in
  24682. X * a couple of places besides the open() calls, (e.g. in the assignment
  24683. X * to openflag in extract.c).  We just #include this rather than
  24684. X * #ifdef them out.
  24685. X *
  24686. X * Written 6/10/87 by rmtodd@uokmax (Richard Todd).
  24687. X *
  24688. X * The names have been changed by John Gilmore, 31 July 1987, since
  24689. X * Richard called it "bsdopen", and really this change was introduced in
  24690. X * AT&T Unix systems before BSD picked it up.
  24691. X */
  24692. X
  24693. X/* Only one of the next three should be specified */
  24694. X#define O_RDONLY     0    /* only allow read */
  24695. X#define    O_WRONLY     1    /* only allow write */
  24696. X#define    O_RDWR         2    /* both are allowed */
  24697. X
  24698. X/* The rest of these can be OR-ed in to the above. */
  24699. X/*
  24700. X * O_NDELAY isn't implemented by the emulator.  It's only useful (to tar) on
  24701. X * systems that have named pipes anyway; it prevents tar's hanging by
  24702. X * opening a named pipe.  We #ifndef it because some systems already have
  24703. X * it defined.
  24704. X */
  24705. X#ifndef O_NDELAY
  24706. X#define O_NDELAY     4    /* don't block on opening devices that would
  24707. X                * block on open -- ignored by emulator. */
  24708. X#endif
  24709. X#define O_CREAT         8    /* create file if needed */
  24710. X#define O_EXCL        16    /* file cannot already exist */
  24711. X#define O_TRUNC        32    /* truncate file on open */
  24712. X#define O_APPEND    64    /* always write at end of file -- ignored by emul */
  24713. X
  24714. X#ifdef EMUL_OPEN3
  24715. X/*
  24716. X * make emulation transparent to rest of file -- redirect all open() calls
  24717. X * to our routine
  24718. X */
  24719. X#define open    open3
  24720. X#endif
  24721. END_OF_FILE
  24722. if test 2639 -ne `wc -c <'open3.h'`; then
  24723.     echo shar: \"'open3.h'\" unpacked with wrong size!
  24724. fi
  24725. # end of 'open3.h'
  24726. fi
  24727. if test -f 'getopt.h' -a "${1}" != "-c" ; then 
  24728.   echo shar: Will not clobber existing file \"'getopt.h'\"
  24729. else
  24730. echo shar: Extracting \"'getopt.h'\" \(4333 characters\)
  24731. sed "s/^X//" >'getopt.h' <<'END_OF_FILE'
  24732. X/* Declarations for getopt.
  24733. X   Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc.
  24734. X
  24735. X   This program is free software; you can redistribute it and/or modify it
  24736. X   under the terms of the GNU General Public License as published by the
  24737. X   Free Software Foundation; either version 2, or (at your option) any
  24738. X   later version.
  24739. X   
  24740. X   This program is distributed in the hope that it will be useful,
  24741. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  24742. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24743. X   GNU General Public License for more details.
  24744. X   
  24745. X   You should have received a copy of the GNU General Public License
  24746. X   along with this program; if not, write to the Free Software
  24747. X   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24748. X
  24749. X#ifndef _GETOPT_H
  24750. X#define _GETOPT_H 1
  24751. X
  24752. X#ifdef    __cplusplus
  24753. Xextern "C" {
  24754. X#endif
  24755. X
  24756. X/* For communication from `getopt' to the caller.
  24757. X   When `getopt' finds an option that takes an argument,
  24758. X   the argument value is returned here.
  24759. X   Also, when `ordering' is RETURN_IN_ORDER,
  24760. X   each non-option ARGV-element is returned here.  */
  24761. X
  24762. Xextern char *optarg;
  24763. X
  24764. X/* Index in ARGV of the next element to be scanned.
  24765. X   This is used for communication to and from the caller
  24766. X   and for communication between successive calls to `getopt'.
  24767. X
  24768. X   On entry to `getopt', zero means this is the first call; initialize.
  24769. X
  24770. X   When `getopt' returns EOF, this is the index of the first of the
  24771. X   non-option elements that the caller should itself scan.
  24772. X
  24773. X   Otherwise, `optind' communicates from one call to the next
  24774. X   how much of ARGV has been scanned so far.  */
  24775. X
  24776. Xextern int optind;
  24777. X
  24778. X/* Callers store zero here to inhibit the error message `getopt' prints
  24779. X   for unrecognized options.  */
  24780. X
  24781. Xextern int opterr;
  24782. X
  24783. X/* Describe the long-named options requested by the application.
  24784. X   The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
  24785. X   of `struct option' terminated by an element containing a name which is
  24786. X   zero.
  24787. X
  24788. X   The field `has_arg' is:
  24789. X   no_argument        (or 0) if the option does not take an argument,
  24790. X   required_argument    (or 1) if the option requires an argument,
  24791. X   optional_argument     (or 2) if the option takes an optional argument.
  24792. X
  24793. X   If the field `flag' is not NULL, it points to a variable that is set
  24794. X   to the value given in the field `val' when the option is found, but
  24795. X   left unchanged if the option is not found.
  24796. X
  24797. X   To have a long-named option do something other than set an `int' to
  24798. X   a compiled-in constant, such as set a value from `optarg', set the
  24799. X   option's `flag' field to zero and its `val' field to a nonzero
  24800. X   value (the equivalent single-letter option character, if there is
  24801. X   one).  For long options that have a zero `flag' field, `getopt'
  24802. X   returns the contents of the `val' field.  */
  24803. X
  24804. Xstruct option
  24805. X{
  24806. X#if    __STDC__
  24807. X  const char *name;
  24808. X#else
  24809. X  char *name;
  24810. X#endif
  24811. X  /* has_arg can't be an enum because some compilers complain about
  24812. X     type mismatches in all the code that assumes it is an int.  */
  24813. X  int has_arg;
  24814. X  int *flag;
  24815. X  int val;
  24816. X};
  24817. X
  24818. X/* Names for the values of the `has_arg' field of `struct option'.  */
  24819. X
  24820. X#define    no_argument        0
  24821. X#define required_argument    1
  24822. X#define optional_argument    2
  24823. X
  24824. X#if __STDC__
  24825. X#if defined(__GNU_LIBRARY__)
  24826. X/* Many other libraries have conflicting prototypes for getopt, with
  24827. X   differences in the consts, in stdlib.h.  To avoid compilation
  24828. X   errors, only prototype getopt for the GNU C library.  */
  24829. Xextern int getopt (int argc, char *const *argv, const char *shortopts);
  24830. X#else /* not __GNU_LIBRARY__ */
  24831. Xextern int getopt ();
  24832. X#endif /* not __GNU_LIBRARY__ */
  24833. Xextern int getopt_long (int argc, char *const *argv, const char *shortopts,
  24834. X                const struct option *longopts, int *longind);
  24835. Xextern int getopt_long_only (int argc, char *const *argv,
  24836. X                 const char *shortopts,
  24837. X                     const struct option *longopts, int *longind);
  24838. X
  24839. X/* Internal only.  Users should not call this directly.  */
  24840. Xextern int _getopt_internal (int argc, char *const *argv,
  24841. X                 const char *shortopts,
  24842. X                     const struct option *longopts, int *longind,
  24843. X                 int long_only);
  24844. X#else /* not __STDC__ */
  24845. Xextern int getopt ();
  24846. Xextern int getopt_long ();
  24847. Xextern int getopt_long_only ();
  24848. X
  24849. Xextern int _getopt_internal ();
  24850. X#endif /* not __STDC__ */
  24851. X
  24852. X#ifdef    __cplusplus
  24853. X}
  24854. X#endif
  24855. X
  24856. X#endif /* _GETOPT_H */
  24857. END_OF_FILE
  24858. if test 4333 -ne `wc -c <'getopt.h'`; then
  24859.     echo shar: \"'getopt.h'\" unpacked with wrong size!
  24860. fi
  24861. # end of 'getopt.h'
  24862. fi
  24863. if test -f 'regex.h' -a "${1}" != "-c" ; then 
  24864.   echo shar: Will not clobber existing file \"'regex.h'\"
  24865. else
  24866. echo shar: Extracting \"'regex.h'\" \(18688 characters\)
  24867. sed "s/^X//" >'regex.h' <<'END_OF_FILE'
  24868. X/* Definitions for data structures and routines for the regular
  24869. X   expression library, version 0.11.
  24870. X
  24871. X   Copyright (C) 1985, 89, 90, 91, 92 Free Software Foundation, Inc.
  24872. X
  24873. X   This program is free software; you can redistribute it and/or modify
  24874. X   it under the terms of the GNU General Public License as published by
  24875. X   the Free Software Foundation; either version 2, or (at your option)
  24876. X   any later version.
  24877. X
  24878. X   This program is distributed in the hope that it will be useful,
  24879. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  24880. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  24881. X   GNU General Public License for more details.
  24882. X
  24883. X   You should have received a copy of the GNU General Public License
  24884. X   along with this program; if not, write to the Free Software
  24885. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  24886. X
  24887. X#ifndef __REGEXP_LIBRARY_H__
  24888. X#define __REGEXP_LIBRARY_H__
  24889. X
  24890. X/* POSIX says that <sys/types.h> must be included (by the caller) before
  24891. X   <regex.h>.  */
  24892. X
  24893. X#ifdef VMS
  24894. X/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
  24895. X   should be there.  */
  24896. X#include <stddef.h>
  24897. X#endif
  24898. X
  24899. X
  24900. X/* The following bits are used to determine the regexp syntax we
  24901. X   recognize.  The set/not-set meanings are chosen so that Emacs syntax
  24902. X   remains the value 0.  The bits are given in alphabetical order, and
  24903. X   the definitions shifted by one from the previous bit; thus, when we
  24904. X   add or remove a bit, only one other definition need change.  */
  24905. Xtypedef unsigned reg_syntax_t;
  24906. X
  24907. X/* If this bit is not set, then \ inside a bracket expression is literal.
  24908. X   If set, then such a \ quotes the following character.  */
  24909. X#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
  24910. X
  24911. X/* If this bit is not set, then + and ? are operators, and \+ and \? are
  24912. X     literals. 
  24913. X   If set, then \+ and \? are operators and + and ? are literals.  */
  24914. X#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
  24915. X
  24916. X/* If this bit is set, then character classes are supported.  They are:
  24917. X     [:alpha:], [:upper:], [:lower:],  [:digit:], [:alnum:], [:xdigit:],
  24918. X     [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
  24919. X   If not set, then character classes are not supported.  */
  24920. X#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
  24921. X
  24922. X/* If this bit is set, then ^ and $ are always anchors (outside bracket
  24923. X     expressions, of course).
  24924. X   If this bit is not set, then it depends:
  24925. X        ^  is an anchor if it is at the beginning of a regular
  24926. X           expression or after an open-group or an alternation operator;
  24927. X        $  is an anchor if it is at the end of a regular expression, or
  24928. X           before a close-group or an alternation operator.  
  24929. X
  24930. X   This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
  24931. X   POSIX draft 11.2 says that * etc. in leading positions is undefined.
  24932. X   We already implemented a previous draft which made those constructs
  24933. X   invalid, though, so we haven't changed the code back.  */
  24934. X#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
  24935. X
  24936. X/* If this bit is set, then special characters are always special
  24937. X     regardless of where they are in the pattern.
  24938. X   If this bit is not set, then special characters are special only in
  24939. X     some contexts; otherwise they are ordinary.  Specifically, 
  24940. X     * + ? and intervals are only special when not after the beginning,
  24941. X     open-group, or alternation operator.  */
  24942. X#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
  24943. X
  24944. X/* If this bit is set, then *, +, ?, and { cannot be first in an re or
  24945. X     immediately after an alternation or begin-group operator.  */
  24946. X#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
  24947. X
  24948. X/* If this bit is set, then . matches newline.
  24949. X   If not set, then it doesn't.  */
  24950. X#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
  24951. X
  24952. X/* If this bit is set, then . doesn't match NUL.
  24953. X   If not set, then it does.  */
  24954. X#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
  24955. X
  24956. X/* If this bit is set, nonmatching lists [^...] do not match newline.
  24957. X   If not set, they do.  */
  24958. X#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
  24959. X
  24960. X/* If this bit is set, either \{...\} or {...} defines an
  24961. X     interval, depending on RE_NO_BK_BRACES. 
  24962. X   If not set, \{, \}, {, and } are literals.  */
  24963. X#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
  24964. X
  24965. X/* If this bit is set, +, ? and | aren't recognized as operators.
  24966. X   If not set, they are.  */
  24967. X#define RE_LIMITED_OPS (RE_INTERVALS << 1)
  24968. X
  24969. X/* If this bit is set, newline is an alternation operator.
  24970. X   If not set, newline is literal.  */
  24971. X#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
  24972. X
  24973. X/* If this bit is set, then `{...}' defines an interval, and \{ and \}
  24974. X     are literals.
  24975. X  If not set, then `\{...\}' defines an interval.  */
  24976. X#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
  24977. X
  24978. X/* If this bit is set, (...) defines a group, and \( and \) are literals.
  24979. X   If not set, \(...\) defines a group, and ( and ) are literals.  */
  24980. X#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
  24981. X
  24982. X/* If this bit is set, then \<digit> matches <digit>.
  24983. X   If not set, then \<digit> is a back-reference.  */
  24984. X#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
  24985. X
  24986. X/* If this bit is set, then | is an alternation operator, and \| is literal. 
  24987. X   If not set, then \| is an alternation operator, and | is literal.  */
  24988. X#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
  24989. X
  24990. X/* If this bit is set, then an ending range point collating higher
  24991. X     than the starting range point, as in [z-a], is invalid.
  24992. X   If not set, then when ending range point collates higher than the
  24993. X     starting range point, the range is ignored.  */
  24994. X#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
  24995. X
  24996. X/* If this bit is set, then an unmatched ) is ordinary.
  24997. X   If not set, then an unmatched ) is invalid.  */
  24998. X#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
  24999. X
  25000. X/* This global variable defines the particular regexp syntax to use (for
  25001. X   some interfaces).  When a regexp is compiled, the syntax used is
  25002. X   stored in the pattern buffer, so changing this does not affect
  25003. X   already-compiled regexps.  */
  25004. Xextern reg_syntax_t re_syntax_options;
  25005. X
  25006. X/* Define combinations of the above bits for the standard possibilities.
  25007. X   (The [[[ comments delimit what gets put into the Texinfo file, so
  25008. X   don't delete them!)  */ 
  25009. X/* [[[begin syntaxes]]] */
  25010. X#define RE_SYNTAX_EMACS 0
  25011. X
  25012. X#define RE_SYNTAX_AWK                            \
  25013. X  (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL            \
  25014. X   | RE_NO_BK_PARENS            | RE_NO_BK_REFS                \
  25015. X   | RE_NO_BK_VBAR               | RE_NO_EMPTY_RANGES            \
  25016. X   | RE_UNMATCHED_RIGHT_PAREN_ORD)
  25017. X
  25018. X#define RE_SYNTAX_POSIX_AWK                         \
  25019. X  (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
  25020. X
  25021. X#define RE_SYNTAX_GREP                            \
  25022. X  (RE_BK_PLUS_QM              | RE_CHAR_CLASSES                \
  25023. X   | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS                \
  25024. X   | RE_NEWLINE_ALT)
  25025. X
  25026. X#define RE_SYNTAX_EGREP                            \
  25027. X  (RE_CHAR_CLASSES        | RE_CONTEXT_INDEP_ANCHORS            \
  25028. X   | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE            \
  25029. X   | RE_NEWLINE_ALT       | RE_NO_BK_PARENS                \
  25030. X   | RE_NO_BK_VBAR)
  25031. X
  25032. X#define RE_SYNTAX_POSIX_EGREP                        \
  25033. X  (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
  25034. X
  25035. X/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff.  */
  25036. X#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
  25037. X
  25038. X#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
  25039. X
  25040. X/* Syntax bits common to both basic and extended POSIX regex syntax.  */
  25041. X#define _RE_SYNTAX_POSIX_COMMON                        \
  25042. X  (RE_CHAR_CLASSES | RE_DOT_NEWLINE      | RE_DOT_NOT_NULL        \
  25043. X   | RE_INTERVALS  | RE_NO_EMPTY_RANGES)
  25044. X
  25045. X#define RE_SYNTAX_POSIX_BASIC                        \
  25046. X  (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
  25047. X
  25048. X/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
  25049. X   RE_LIMITED_OPS, i.e., \? \+ \| are not recognized.  Actually, this
  25050. X   isn't minimal, since other operators, such as \`, aren't disabled.  */
  25051. X#define RE_SYNTAX_POSIX_MINIMAL_BASIC                    \
  25052. X  (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
  25053. X
  25054. X#define RE_SYNTAX_POSIX_EXTENDED                    \
  25055. X  (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS            \
  25056. X   | RE_CONTEXT_INDEP_OPS  | RE_NO_BK_BRACES                \
  25057. X   | RE_NO_BK_PARENS       | RE_NO_BK_VBAR                \
  25058. X   | RE_UNMATCHED_RIGHT_PAREN_ORD)
  25059. X
  25060. X/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
  25061. X   replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added.  */
  25062. X#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED                \
  25063. X  (_RE_SYNTAX_POSIX_COMMON  | RE_CONTEXT_INDEP_ANCHORS            \
  25064. X   | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES                \
  25065. X   | RE_NO_BK_PARENS        | RE_NO_BK_REFS                \
  25066. X   | RE_NO_BK_VBAR        | RE_UNMATCHED_RIGHT_PAREN_ORD)
  25067. X/* [[[end syntaxes]]] */
  25068. X
  25069. X/* Maximum number of duplicates an interval can allow.  Some systems
  25070. X   (erroneously) define this in other header files, but we want our
  25071. X   value, so remove any previous define.  */
  25072. X#ifdef RE_DUP_MAX
  25073. X#undef RE_DUP_MAX
  25074. X#endif
  25075. X#define RE_DUP_MAX ((1 << 15) - 1) 
  25076. X
  25077. X
  25078. X/* POSIX `cflags' bits (i.e., information for `regcomp').  */
  25079. X
  25080. X/* If this bit is set, then use extended regular expression syntax.
  25081. X   If not set, then use basic regular expression syntax.  */
  25082. X#define REG_EXTENDED 1
  25083. X
  25084. X/* If this bit is set, then ignore case when matching.
  25085. X   If not set, then case is significant.  */
  25086. X#define REG_ICASE (REG_EXTENDED << 1)
  25087. X/* If this bit is set, then anchors do not match at newline
  25088. X     characters in the string.
  25089. X   If not set, then anchors do match at newlines.  */
  25090. X#define REG_NEWLINE (REG_ICASE << 1)
  25091. X
  25092. X/* If this bit is set, then report only success or fail in regexec.
  25093. X   If not set, then returns differ between not matching and errors.  */
  25094. X#define REG_NOSUB (REG_NEWLINE << 1)
  25095. X
  25096. X
  25097. X/* POSIX `eflags' bits (i.e., information for regexec).  */
  25098. X
  25099. X/* If this bit is set, then the beginning-of-line operator doesn't match
  25100. X     the beginning of the string (presumably because it's not the
  25101. X     beginning of a line).
  25102. X   If not set, then the beginning-of-line operator does match the
  25103. X     beginning of the string.  */
  25104. X#define REG_NOTBOL 1
  25105. X
  25106. X/* Like REG_NOTBOL, except for the end-of-line.  */
  25107. X#define REG_NOTEOL (1 << 1)
  25108. X
  25109. X
  25110. X/* If any error codes are removed, changed, or added, update the
  25111. X   `re_error_msg' table in regex.c.  */
  25112. Xtypedef enum
  25113. X{
  25114. X  REG_NOERROR = 0,    /* Success.  */
  25115. X  REG_NOMATCH,        /* Didn't find a match (for regexec).  */
  25116. X
  25117. X  /* POSIX regcomp return error codes.  (In the order listed in the
  25118. X     standard.)  */
  25119. X  REG_BADPAT,        /* Invalid pattern.  */
  25120. X  REG_ECOLLATE,        /* Not implemented.  */
  25121. X  REG_ECTYPE,        /* Invalid character class name.  */
  25122. X  REG_EESCAPE,        /* Trailing backslash.  */
  25123. X  REG_ESUBREG,        /* Invalid back reference.  */
  25124. X  REG_EBRACK,        /* Unmatched left bracket.  */
  25125. X  REG_EPAREN,        /* Parenthesis imbalance.  */ 
  25126. X  REG_EBRACE,        /* Unmatched \{.  */
  25127. X  REG_BADBR,        /* Invalid contents of \{\}.  */
  25128. X  REG_ERANGE,        /* Invalid range end.  */
  25129. X  REG_ESPACE,        /* Ran out of memory.  */
  25130. X  REG_BADRPT,        /* No preceding re for repetition op.  */
  25131. X
  25132. X  /* Error codes we've added.  */
  25133. X  REG_EEND,        /* Premature end.  */
  25134. X  REG_ESIZE,        /* Compiled pattern bigger than 2^16 bytes.  */
  25135. X  REG_ERPAREN        /* Unmatched ) or \); not returned from regcomp.  */
  25136. X} reg_errcode_t;
  25137. X
  25138. X/* This data structure represents a compiled pattern.  Before calling
  25139. X   the pattern compiler, the fields `buffer', `allocated', `fastmap',
  25140. X   `translate', and `no_sub' can be set.  After the pattern has been
  25141. X   compiled, the `re_nsub' field is available.  All other fields are
  25142. X   private to the regex routines.  */
  25143. X
  25144. Xstruct re_pattern_buffer
  25145. X{
  25146. X/* [[[begin pattern_buffer]]] */
  25147. X    /* Space that holds the compiled pattern.  It is declared as
  25148. X          `unsigned char *' because its elements are
  25149. X           sometimes used as array indexes.  */
  25150. X  unsigned char *buffer;
  25151. X
  25152. X    /* Number of bytes to which `buffer' points.  */
  25153. X  unsigned long allocated;
  25154. X
  25155. X    /* Number of bytes actually used in `buffer'.  */
  25156. X  unsigned long used;    
  25157. X
  25158. X        /* Syntax setting with which the pattern was compiled.  */
  25159. X  reg_syntax_t syntax;
  25160. X
  25161. X        /* Pointer to a fastmap, if any, otherwise zero.  re_search uses
  25162. X           the fastmap, if there is one, to skip over impossible
  25163. X           starting points for matches.  */
  25164. X  char *fastmap;
  25165. X
  25166. X        /* Either a translate table to apply to all characters before
  25167. X           comparing them, or zero for no translation.  The translation
  25168. X           is applied to a pattern when it is compiled and to a string
  25169. X           when it is matched.  */
  25170. X  char *translate;
  25171. X
  25172. X    /* Number of subexpressions found by the compiler.  */
  25173. X  size_t re_nsub;
  25174. X
  25175. X        /* Zero if this pattern cannot match the empty string, one else.
  25176. X           Well, in truth it's used only in `re_search_2', to see
  25177. X           whether or not we should use the fastmap, so we don't set
  25178. X           this absolutely perfectly; see `re_compile_fastmap' (the
  25179. X           `duplicate' case).  */
  25180. X  unsigned can_be_null : 1;
  25181. X
  25182. X        /* If REGS_UNALLOCATED, allocate space in the `regs' structure
  25183. X             for `max (RE_NREGS, re_nsub + 1)' groups.
  25184. X           If REGS_REALLOCATE, reallocate space if necessary.
  25185. X           If REGS_FIXED, use what's there.  */
  25186. X#define REGS_UNALLOCATED 0
  25187. X#define REGS_REALLOCATE 1
  25188. X#define REGS_FIXED 2
  25189. X  unsigned regs_allocated : 2;
  25190. X
  25191. X        /* Set to zero when `regex_compile' compiles a pattern; set to one
  25192. X           by `re_compile_fastmap' if it updates the fastmap.  */
  25193. X  unsigned fastmap_accurate : 1;
  25194. X
  25195. X        /* If set, `re_match_2' does not return information about
  25196. X           subexpressions.  */
  25197. X  unsigned no_sub : 1;
  25198. X
  25199. X        /* If set, a beginning-of-line anchor doesn't match at the
  25200. X           beginning of the string.  */ 
  25201. X  unsigned not_bol : 1;
  25202. X
  25203. X        /* Similarly for an end-of-line anchor.  */
  25204. X  unsigned not_eol : 1;
  25205. X
  25206. X        /* If true, an anchor at a newline matches.  */
  25207. X  unsigned newline_anchor : 1;
  25208. X
  25209. X/* [[[end pattern_buffer]]] */
  25210. X};
  25211. X
  25212. Xtypedef struct re_pattern_buffer regex_t;
  25213. X
  25214. X
  25215. X/* search.c (search_buffer) in Emacs needs this one opcode value.  It is
  25216. X   defined both in `regex.c' and here.  */
  25217. X#define RE_EXACTN_VALUE 1
  25218. X
  25219. X/* Type for byte offsets within the string.  POSIX mandates this.  */
  25220. Xtypedef int regoff_t;
  25221. X
  25222. X
  25223. X/* This is the structure we store register match data in.  See
  25224. X   regex.texinfo for a full description of what registers match.  */
  25225. Xstruct re_registers
  25226. X{
  25227. X  unsigned num_regs;
  25228. X  regoff_t *start;
  25229. X  regoff_t *end;
  25230. X};
  25231. X
  25232. X
  25233. X/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
  25234. X   `re_match_2' returns information about at least this many registers
  25235. X   the first time a `regs' structure is passed.  */
  25236. X#ifndef RE_NREGS
  25237. X#define RE_NREGS 30
  25238. X#endif
  25239. X
  25240. X
  25241. X/* POSIX specification for registers.  Aside from the different names than
  25242. X   `re_registers', POSIX uses an array of structures, instead of a
  25243. X   structure of arrays.  */
  25244. Xtypedef struct
  25245. X{
  25246. X  regoff_t rm_so;  /* Byte offset from string's start to substring's start.  */
  25247. X  regoff_t rm_eo;  /* Byte offset from string's start to substring's end.  */
  25248. X} regmatch_t;
  25249. X
  25250. X/* Declarations for routines.  */
  25251. X
  25252. X/* To avoid duplicating every routine declaration -- once with a
  25253. X   prototype (if we are ANSI), and once without (if we aren't) -- we
  25254. X   use the following macro to declare argument types.  This
  25255. X   unfortunately clutters up the declarations a bit, but I think it's
  25256. X   worth it.  */
  25257. X
  25258. X#if __STDC__
  25259. X
  25260. X#define _RE_ARGS(args) args
  25261. X
  25262. X#else /* not __STDC__ */
  25263. X
  25264. X#define _RE_ARGS(args) ()
  25265. X
  25266. X#endif /* not __STDC__ */
  25267. X
  25268. X/* Sets the current default syntax to SYNTAX, and return the old syntax.
  25269. X   You can also simply assign to the `re_syntax_options' variable.  */
  25270. Xextern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
  25271. X
  25272. X/* Compile the regular expression PATTERN, with length LENGTH
  25273. X   and syntax given by the global `re_syntax_options', into the buffer
  25274. X   BUFFER.  Return NULL if successful, and an error string if not.  */
  25275. Xextern const char *re_compile_pattern
  25276. X  _RE_ARGS ((const char *pattern, int length,
  25277. X             struct re_pattern_buffer *buffer));
  25278. X
  25279. X
  25280. X/* Compile a fastmap for the compiled pattern in BUFFER; used to
  25281. X   accelerate searches.  Return 0 if successful and -2 if was an
  25282. X   internal error.  */
  25283. Xextern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
  25284. X
  25285. X
  25286. X/* Search in the string STRING (with length LENGTH) for the pattern
  25287. X   compiled into BUFFER.  Start searching at position START, for RANGE
  25288. X   characters.  Return the starting position of the match, -1 for no
  25289. X   match, or -2 for an internal error.  Also return register
  25290. X   information in REGS (if REGS and BUFFER->no_sub are nonzero).  */
  25291. Xextern int re_search
  25292. X  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
  25293. X            int length, int start, int range, struct re_registers *regs));
  25294. X
  25295. X
  25296. X/* Like `re_search', but search in the concatenation of STRING1 and
  25297. X   STRING2.  Also, stop searching at index START + STOP.  */
  25298. Xextern int re_search_2
  25299. X  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
  25300. X             int length1, const char *string2, int length2,
  25301. X             int start, int range, struct re_registers *regs, int stop));
  25302. X
  25303. X
  25304. X/* Like `re_search', but return how many characters in STRING the regexp
  25305. X   in BUFFER matched, starting at position START.  */
  25306. Xextern int re_match
  25307. X  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
  25308. X             int length, int start, struct re_registers *regs));
  25309. X
  25310. X
  25311. X/* Relates to `re_match' as `re_search_2' relates to `re_search'.  */
  25312. Xextern int re_match_2 
  25313. X  _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
  25314. X             int length1, const char *string2, int length2,
  25315. X             int start, struct re_registers *regs, int stop));
  25316. X
  25317. X
  25318. X/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
  25319. X   ENDS.  Subsequent matches using BUFFER and REGS will use this memory
  25320. X   for recording register information.  STARTS and ENDS must be
  25321. X   allocated with malloc, and must each be at least `NUM_REGS * sizeof
  25322. X   (regoff_t)' bytes long.
  25323. X
  25324. X   If NUM_REGS == 0, then subsequent matches should allocate their own
  25325. X   register data.
  25326. X
  25327. X   Unless this function is called, the first search or match using
  25328. X   PATTERN_BUFFER will allocate its own register data, without
  25329. X   freeing the old data.  */
  25330. Xextern void re_set_registers
  25331. X  _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
  25332. X             unsigned num_regs, regoff_t *starts, regoff_t *ends));
  25333. X
  25334. X/* 4.2 bsd compatibility.  */
  25335. Xextern char *re_comp _RE_ARGS ((const char *));
  25336. Xextern int re_exec _RE_ARGS ((const char *));
  25337. X
  25338. X/* POSIX compatibility.  */
  25339. Xextern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
  25340. Xextern int regexec
  25341. X  _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
  25342. X             regmatch_t pmatch[], int eflags));
  25343. Xextern size_t regerror
  25344. X  _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
  25345. X             size_t errbuf_size));
  25346. Xextern void regfree _RE_ARGS ((regex_t *preg));
  25347. X
  25348. X#endif /* not __REGEXP_LIBRARY_H__ */
  25349. X
  25350. X/*
  25351. XLocal variables:
  25352. Xmake-backup-files: t
  25353. Xversion-control: t
  25354. Xtrim-versions-without-asking: nil
  25355. XEnd:
  25356. X*/
  25357. END_OF_FILE
  25358. if test 18688 -ne `wc -c <'regex.h'`; then
  25359.     echo shar: \"'regex.h'\" unpacked with wrong size!
  25360. fi
  25361. # end of 'regex.h'
  25362. fi
  25363. if test -f 'rmt.h' -a "${1}" != "-c" ; then 
  25364.   echo shar: Will not clobber existing file \"'rmt.h'\"
  25365. else
  25366. echo shar: Extracting \"'rmt.h'\" \(3321 characters\)
  25367. sed "s/^X//" >'rmt.h' <<'END_OF_FILE'
  25368. X/* Definitions for communicating with a remote tape drive.
  25369. X   Copyright (C) 1988, 1992 Free Software Foundation, Inc.
  25370. X
  25371. X   This program is free software; you can redistribute it and/or modify
  25372. X   it under the terms of the GNU General Public License as published by
  25373. X   the Free Software Foundation; either version 2, or (at your option)
  25374. X   any later version.
  25375. X
  25376. X   This program is distributed in the hope that it will be useful,
  25377. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  25378. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25379. X   GNU General Public License for more details.
  25380. X
  25381. X   You should have received a copy of the GNU General Public License
  25382. X   along with this program; if not, write to the Free Software
  25383. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  25384. X
  25385. X#ifdef HAVE_UNISTD_H
  25386. X#include <unistd.h>
  25387. X#endif
  25388. X
  25389. X#if !defined(_POSIX_VERSION)
  25390. X#ifdef __MSDOS__
  25391. X#include <io.h>
  25392. X#else /* !__MSDOS__ */
  25393. Xextern off_t lseek ();
  25394. X#endif /* __MSDOS__ */
  25395. X#endif /* _POSIX_VERSION */
  25396. X
  25397. X#ifdef NO_REMOTE
  25398. X#define _isrmt(f)    0
  25399. X#define rmtopen        open
  25400. X#define rmtaccess    access
  25401. X#define rmtstat        stat
  25402. X#define rmtcreat    creat
  25403. X#define rmtlstat    lstat
  25404. X#define rmtread        read
  25405. X#define rmtwrite    write
  25406. X#define rmtlseek    lseek
  25407. X#define rmtclose    close
  25408. X#define rmtioctl    ioctl
  25409. X#define rmtdup        dup
  25410. X#define rmtfstat    fstat
  25411. X#define rmtfcntl    fcntl
  25412. X#define rmtisatty    isatty
  25413. X
  25414. X#else /* !NO_REMOTE */
  25415. X
  25416. X#define __REM_BIAS    128
  25417. X#define RMTIOCTL
  25418. X
  25419. X#ifndef O_CREAT
  25420. X#define O_CREAT    01000
  25421. X#endif
  25422. X
  25423. Xextern char *__rmt_path;
  25424. X
  25425. X#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
  25426. X#include <string.h>
  25427. X#ifndef index
  25428. X#define index strchr
  25429. X#endif
  25430. X#else
  25431. Xextern char *index ();
  25432. X#endif
  25433. X
  25434. X#define _remdev(path)    (!f_force_local && (__rmt_path=index(path, ':')))
  25435. X#define _isrmt(fd)        ((fd) >= __REM_BIAS)
  25436. X
  25437. X#define rmtopen(path,oflag,mode) (_remdev(path) ? __rmt_open(path, oflag, mode, __REM_BIAS) : open(path, oflag, mode))
  25438. X#define rmtaccess(path, amode)    (_remdev(path) ? 0 : access(path, amode))
  25439. X#define rmtstat(path, buf)    (_remdev(path) ? (errno = EOPNOTSUPP), -1 : stat(path, buf))
  25440. X#define rmtcreat(path, mode)    (_remdev(path) ? __rmt_open (path, 1 | O_CREAT, mode, __REM_BIAS) : creat(path, mode))
  25441. X#define rmtlstat(path,buf)    (_remdev(path) ? (errno = EOPNOTSUPP), -1 : lstat(path,buf))
  25442. X
  25443. X#define rmtread(fd, buf, n)    (_isrmt(fd) ? __rmt_read(fd - __REM_BIAS, buf, n) : read(fd, buf, n))
  25444. X#define rmtwrite(fd, buf, n)    (_isrmt(fd) ? __rmt_write(fd - __REM_BIAS, buf, n) : write(fd, buf, n))
  25445. X#define rmtlseek(fd, off, wh)    (_isrmt(fd) ? __rmt_lseek(fd - __REM_BIAS, off, wh) : lseek(fd, off, wh))
  25446. X#define rmtclose(fd)        (_isrmt(fd) ? __rmt_close(fd - __REM_BIAS) : close(fd))
  25447. X#ifdef RMTIOCTL
  25448. X#define rmtioctl(fd,req,arg)    (_isrmt(fd) ? __rmt_ioctl(fd - __REM_BIAS, req, arg) : ioctl(fd, req, arg))
  25449. X#else
  25450. X#define rmtioctl(fd,req,arg)    (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : ioctl(fd, req, arg))
  25451. X#endif
  25452. X#define rmtdup(fd)        (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : dup(fd))
  25453. X#define rmtfstat(fd, buf)    (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fstat(fd, buf))
  25454. X#define rmtfcntl(fd,cmd,arg)    (_isrmt(fd) ? (errno = EOPNOTSUPP), -1 : fcntl (fd, cmd, arg))
  25455. X#define rmtisatty(fd)        (_isrmt(fd) ? 0 : isatty(fd))
  25456. X
  25457. X#undef RMTIOCTL
  25458. X
  25459. Xint __rmt_open ();
  25460. Xint __rmt_close ();
  25461. Xint __rmt_read ();
  25462. Xint __rmt_write ();
  25463. Xlong __rmt_lseek ();
  25464. Xint __rmt_ioctl ();
  25465. X#endif /* !NO_REMOTE */
  25466. END_OF_FILE
  25467. if test 3321 -ne `wc -c <'rmt.h'`; then
  25468.     echo shar: \"'rmt.h'\" unpacked with wrong size!
  25469. fi
  25470. # end of 'rmt.h'
  25471. fi
  25472. if test -f 'rmt.c' -a "${1}" != "-c" ; then 
  25473.   echo shar: Will not clobber existing file \"'rmt.c'\"
  25474. else
  25475. echo shar: Extracting \"'rmt.c'\" \(5987 characters\)
  25476. sed "s/^X//" >'rmt.c' <<'END_OF_FILE'
  25477. X/*
  25478. X * Copyright (c) 1983 Regents of the University of California.
  25479. X * All rights reserved.
  25480. X *
  25481. X * Redistribution and use in source and binary forms are permitted
  25482. X * provided that the above copyright notice and this paragraph are
  25483. X * duplicated in all such forms and that any documentation,
  25484. X * advertising materials, and other materials related to such
  25485. X * distribution and use acknowledge that the software was developed
  25486. X * by the University of California, Berkeley.  The name of the
  25487. X * University may not be used to endorse or promote products derived
  25488. X * from this software without specific prior written permission.
  25489. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  25490. X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  25491. X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  25492. X */
  25493. X
  25494. X#ifndef lint
  25495. Xchar copyright[] =
  25496. X"@(#) Copyright (c) 1983 Regents of the University of California.\n\
  25497. X All rights reserved.\n";
  25498. X#endif /* not lint */
  25499. X
  25500. X/*
  25501. X * rmt
  25502. X */
  25503. X#include <stdio.h>
  25504. X#include <sgtty.h>
  25505. X#include <sys/types.h>
  25506. X#include <sys/socket.h>
  25507. X#ifdef HAVE_SYS_GENTAPE_H    /* e.g., ISC UNIX */
  25508. X#include <sys/gentape.h>
  25509. X#else
  25510. X#include <sys/mtio.h>
  25511. X#endif
  25512. X#include <errno.h>
  25513. X
  25514. X#if defined (_I386) && defined (_AIX)
  25515. X#include <fcntl.h>
  25516. X#endif
  25517. X
  25518. X#ifdef HAVE_UNISTD_H
  25519. X#include <unistd.h>
  25520. X#else
  25521. Xlong lseek ();
  25522. X#endif
  25523. X
  25524. X#ifdef STDC_HEADERS
  25525. X#include <string.h>
  25526. X#include <stdlib.h>
  25527. X#else
  25528. Xextern char *malloc ();
  25529. X#endif
  25530. X
  25531. Xint tape = -1;
  25532. X
  25533. Xchar *record;
  25534. Xint maxrecsize = -1;
  25535. Xchar *checkbuf ();
  25536. Xvoid getstring ();
  25537. Xvoid error ();
  25538. X
  25539. X#define    SSIZE    64
  25540. Xchar device[SSIZE];
  25541. Xchar count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
  25542. X
  25543. Xextern errno;
  25544. Xextern char *sys_errlist[];
  25545. Xchar resp[BUFSIZ];
  25546. X
  25547. XFILE *debug;
  25548. X#define    DEBUG(f)    if (debug) fprintf(debug, f)
  25549. X#define    DEBUG1(f,a)    if (debug) fprintf(debug, f, a)
  25550. X#define    DEBUG2(f,a1,a2)    if (debug) fprintf(debug, f, a1, a2)
  25551. X
  25552. Xint
  25553. Xmain (argc, argv)
  25554. X     int argc;
  25555. X     char **argv;
  25556. X{
  25557. X  int rval;
  25558. X  char c;
  25559. X  int n, i, cc;
  25560. X
  25561. X  argc--, argv++;
  25562. X  if (argc > 0)
  25563. X    {
  25564. X      debug = fopen (*argv, "w");
  25565. X      if (debug == 0)
  25566. X    exit (1);
  25567. X      (void) setbuf (debug, (char *) 0);
  25568. X    }
  25569. Xtop:
  25570. X  errno = 0;
  25571. X  rval = 0;
  25572. X  if (read (0, &c, 1) != 1)
  25573. X    exit (0);
  25574. X  switch (c)
  25575. X    {
  25576. X
  25577. X    case 'O':
  25578. X      if (tape >= 0)
  25579. X    (void) close (tape);
  25580. X      getstring (device);
  25581. X      getstring (mode);
  25582. X      DEBUG2 ("rmtd: O %s %s\n", device, mode);
  25583. X#if defined (i386) && defined (AIX)
  25584. X      /* This is alleged to fix a byte ordering problem. */
  25585. X      /* I'm quite suspicious if it's right. -- mib */
  25586. X      {
  25587. X    int oflag = atoi (mode);
  25588. X    int nflag = 0;
  25589. X    if ((oflag & 3) == 0)
  25590. X      nflag |= O_RDONLY;
  25591. X    if (oflag & 1)
  25592. X      nflag |= O_WRONLY;
  25593. X    if (oflag & 2)
  25594. X      nflag |= O_RDWR;
  25595. X    if (oflag & 0x0008)
  25596. X      nflag |= O_APPEND;
  25597. X    if (oflag & 0x0200)
  25598. X      nflag |= O_CREAT;
  25599. X    if (oflag & 0x0400)
  25600. X      nflag |= O_TRUNC;
  25601. X    if (oflag & 0x0800)
  25602. X      nflag |= O_EXCL;
  25603. X    tape = open (device, nflag, 0666);
  25604. X      }
  25605. X#else
  25606. X      tape = open (device, atoi (mode), 0666);
  25607. X#endif
  25608. X      if (tape < 0)
  25609. X    goto ioerror;
  25610. X      goto respond;
  25611. X
  25612. X    case 'C':
  25613. X      DEBUG ("rmtd: C\n");
  25614. X      getstring (device);    /* discard */
  25615. X      if (close (tape) < 0)
  25616. X    goto ioerror;
  25617. X      tape = -1;
  25618. X      goto respond;
  25619. X
  25620. X    case 'L':
  25621. X      getstring (count);
  25622. X      getstring (pos);
  25623. X      DEBUG2 ("rmtd: L %s %s\n", count, pos);
  25624. X      rval = lseek (tape, (long) atoi (count), atoi (pos));
  25625. X      if (rval < 0)
  25626. X    goto ioerror;
  25627. X      goto respond;
  25628. X
  25629. X    case 'W':
  25630. X      getstring (count);
  25631. X      n = atoi (count);
  25632. X      DEBUG1 ("rmtd: W %s\n", count);
  25633. X      record = checkbuf (record, n);
  25634. X      for (i = 0; i < n; i += cc)
  25635. X    {
  25636. X      cc = read (0, &record[i], n - i);
  25637. X      if (cc <= 0)
  25638. X        {
  25639. X          DEBUG ("rmtd: premature eof\n");
  25640. X          exit (2);
  25641. X        }
  25642. X    }
  25643. X      rval = write (tape, record, n);
  25644. X      if (rval < 0)
  25645. X    goto ioerror;
  25646. X      goto respond;
  25647. X
  25648. X    case 'R':
  25649. X      getstring (count);
  25650. X      DEBUG1 ("rmtd: R %s\n", count);
  25651. X      n = atoi (count);
  25652. X      record = checkbuf (record, n);
  25653. X      rval = read (tape, record, n);
  25654. X      if (rval < 0)
  25655. X    goto ioerror;
  25656. X      (void) sprintf (resp, "A%d\n", rval);
  25657. X      (void) write (1, resp, strlen (resp));
  25658. X      (void) write (1, record, rval);
  25659. X      goto top;
  25660. X
  25661. X    case 'I':
  25662. X      getstring (op);
  25663. X      getstring (count);
  25664. X      DEBUG2 ("rmtd: I %s %s\n", op, count);
  25665. X#ifdef MTIOCTOP
  25666. X      {
  25667. X    struct mtop mtop;
  25668. X    mtop.mt_op = atoi (op);
  25669. X    mtop.mt_count = atoi (count);
  25670. X    if (ioctl (tape, MTIOCTOP, (char *) &mtop) < 0)
  25671. X      goto ioerror;
  25672. X    rval = mtop.mt_count;
  25673. X      }
  25674. X#endif
  25675. X      goto respond;
  25676. X
  25677. X    case 'S':            /* status */
  25678. X      DEBUG ("rmtd: S\n");
  25679. X      {
  25680. X#ifdef MTIOCGET
  25681. X    struct mtget mtget;
  25682. X    if (ioctl (tape, MTIOCGET, (char *) &mtget) < 0)
  25683. X      goto ioerror;
  25684. X    rval = sizeof (mtget);
  25685. X    (void) sprintf (resp, "A%d\n", rval);
  25686. X    (void) write (1, resp, strlen (resp));
  25687. X    (void) write (1, (char *) &mtget, sizeof (mtget));
  25688. X#endif
  25689. X    goto top;
  25690. X      }
  25691. X
  25692. X    default:
  25693. X      DEBUG1 ("rmtd: garbage command %c\n", c);
  25694. X      exit (3);
  25695. X    }
  25696. Xrespond:
  25697. X  DEBUG1 ("rmtd: A %d\n", rval);
  25698. X  (void) sprintf (resp, "A%d\n", rval);
  25699. X  (void) write (1, resp, strlen (resp));
  25700. X  goto top;
  25701. Xioerror:
  25702. X  error (errno);
  25703. X  goto top;
  25704. X}
  25705. X
  25706. Xvoid
  25707. Xgetstring (bp)
  25708. X     char *bp;
  25709. X{
  25710. X  int i;
  25711. X  char *cp = bp;
  25712. X
  25713. X  for (i = 0; i < SSIZE; i++)
  25714. X    {
  25715. X      if (read (0, cp + i, 1) != 1)
  25716. X    exit (0);
  25717. X      if (cp[i] == '\n')
  25718. X    break;
  25719. X    }
  25720. X  cp[i] = '\0';
  25721. X}
  25722. X
  25723. Xchar *
  25724. Xcheckbuf (record, size)
  25725. X     char *record;
  25726. X     int size;
  25727. X{
  25728. X  if (size <= maxrecsize)
  25729. X    return (record);
  25730. X  if (record != 0)
  25731. X    free (record);
  25732. X  record = malloc (size);
  25733. X  if (record == 0)
  25734. X    {
  25735. X      DEBUG ("rmtd: cannot allocate buffer space\n");
  25736. X      exit (4);
  25737. X    }
  25738. X  maxrecsize = size;
  25739. X#ifdef SO_RCVBUF
  25740. X  while (size > 1024 &&
  25741. X   setsockopt (0, SOL_SOCKET, SO_RCVBUF, (char *) &size, sizeof (size)) < 0)
  25742. X    size -= 1024;
  25743. X#else
  25744. X  size = 1 + ((size - 1) % 1024);
  25745. X#endif
  25746. X  return (record);
  25747. X}
  25748. X
  25749. Xvoid
  25750. Xerror (num)
  25751. X     int num;
  25752. X{
  25753. X
  25754. X  DEBUG2 ("rmtd: E %d (%s)\n", num, sys_errlist[num]);
  25755. X  (void) sprintf (resp, "E%d\n%s\n", num, sys_errlist[num]);
  25756. X  (void) write (1, resp, strlen (resp));
  25757. X}
  25758. END_OF_FILE
  25759. if test 5987 -ne `wc -c <'rmt.c'`; then
  25760.     echo shar: \"'rmt.c'\" unpacked with wrong size!
  25761. fi
  25762. # end of 'rmt.c'
  25763. fi
  25764. if test -f 'rtapelib.c' -a "${1}" != "-c" ; then 
  25765.   echo shar: Will not clobber existing file \"'rtapelib.c'\"
  25766. else
  25767. echo shar: Extracting \"'rtapelib.c'\" \(14007 characters\)
  25768. sed "s/^X//" >'rtapelib.c' <<'END_OF_FILE'
  25769. X/* Functions for communicating with a remote tape drive.
  25770. X   Copyright (C) 1988, 1992 Free Software Foundation, Inc.
  25771. X
  25772. X   This program is free software; you can redistribute it and/or modify
  25773. X   it under the terms of the GNU General Public License as published by
  25774. X   the Free Software Foundation; either version 2, or (at your option)
  25775. X   any later version.
  25776. X
  25777. X   This program is distributed in the hope that it will be useful,
  25778. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  25779. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  25780. X   GNU General Public License for more details.
  25781. X
  25782. X   You should have received a copy of the GNU General Public License
  25783. X   along with this program; if not, write to the Free Software
  25784. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  25785. X
  25786. X/* The man page rmt(8) for /etc/rmt documents the remote mag tape
  25787. X   protocol which rdump and rrestore use.  Unfortunately, the man
  25788. X   page is *WRONG*.  The author of the routines I'm including originally
  25789. X   wrote his code just based on the man page, and it didn't work, so he
  25790. X   went to the rdump source to figure out why.  The only thing he had to
  25791. X   change was to check for the 'F' return code in addition to the 'E',
  25792. X   and to separate the various arguments with \n instead of a space.  I
  25793. X   personally don't think that this is much of a problem, but I wanted to
  25794. X   point it out. -- Arnold Robbins
  25795. X
  25796. X   Originally written by Jeff Lee, modified some by Arnold Robbins.
  25797. X   Redone as a library that can replace open, read, write, etc., by
  25798. X   Fred Fish, with some additional work by Arnold Robbins.
  25799. X   Modified to make all rmtXXX calls into macros for speed by Jay Fenlason.
  25800. X   Use -DHAVE_NETDB_H for rexec code, courtesy of Dan Kegel, srs!dan.  */
  25801. X
  25802. X#include <stdio.h>
  25803. X#include <sys/types.h>
  25804. X#include <signal.h>
  25805. X
  25806. X#ifdef HAVE_SYS_MTIO_H
  25807. X#include <sys/ioctl.h>
  25808. X#include <sys/mtio.h>
  25809. X#endif
  25810. X
  25811. X#ifdef HAVE_NETDB_H
  25812. X#include <netdb.h>
  25813. X#endif
  25814. X
  25815. X#include <errno.h>
  25816. X#include <setjmp.h>
  25817. X#include <sys/stat.h>
  25818. X
  25819. X#ifndef errno
  25820. Xextern int errno;
  25821. X#endif
  25822. X
  25823. X#ifdef HAVE_UNISTD_H
  25824. X#include <unistd.h>
  25825. X#endif
  25826. X#ifdef STDC_HEADERS
  25827. X#include <string.h>
  25828. X#include <stdlib.h>
  25829. X#endif
  25830. X
  25831. X/* Maximum size of a fully qualified host name.  */
  25832. X#define MAXHOSTLEN 257
  25833. X
  25834. X/* Size of buffers for reading and writing commands to rmt.
  25835. X   (An arbitrary limit.)  */
  25836. X#define CMDBUFSIZE 64
  25837. X
  25838. X#ifndef RETSIGTYPE
  25839. X#define RETSIGTYPE void
  25840. X#endif
  25841. X
  25842. X/* Maximum number of simultaneous remote tape connections.
  25843. X   (Another arbitrary limit.)  */
  25844. X#define MAXUNIT    4
  25845. X
  25846. X/* Return the parent's read side of remote tape connection FILDES.  */
  25847. X#define READ(fildes) (from_rmt[fildes][0])
  25848. X
  25849. X/* Return the parent's write side of remote tape connection FILDES.  */
  25850. X#define WRITE(fildes) (to_rmt[fildes][1])
  25851. X
  25852. X/* The pipes for receiving data from remote tape drives.  */
  25853. Xstatic int from_rmt[MAXUNIT][2] =
  25854. X{-1, -1, -1, -1, -1, -1, -1, -1};
  25855. X
  25856. X/* The pipes for sending data to remote tape drives.  */
  25857. Xstatic int to_rmt[MAXUNIT][2] =
  25858. X{-1, -1, -1, -1, -1, -1, -1, -1};
  25859. X
  25860. X/* Temporary variable used by macros in rmt.h.  */
  25861. Xchar *__rmt_path;
  25862. X
  25863. X/* Close remote tape connection FILDES.  */
  25864. X
  25865. Xstatic void
  25866. X_rmt_shutdown (fildes)
  25867. X     int fildes;
  25868. X{
  25869. X  close (READ (fildes));
  25870. X  close (WRITE (fildes));
  25871. X  READ (fildes) = -1;
  25872. X  WRITE (fildes) = -1;
  25873. X}
  25874. X
  25875. X/* Attempt to perform the remote tape command specified in BUF
  25876. X   on remote tape connection FILDES.
  25877. X   Return 0 if successful, -1 on error.  */
  25878. X
  25879. Xstatic int
  25880. Xcommand (fildes, buf)
  25881. X     int fildes;
  25882. X     char *buf;
  25883. X{
  25884. X  register int buflen;
  25885. X  RETSIGTYPE (*pipe_handler) ();
  25886. X
  25887. X  /* Save the current pipe handler and try to make the request.  */
  25888. X
  25889. X  pipe_handler = signal (SIGPIPE, SIG_IGN);
  25890. X  buflen = strlen (buf);
  25891. X  if (write (WRITE (fildes), buf, buflen) == buflen)
  25892. X    {
  25893. X      signal (SIGPIPE, pipe_handler);
  25894. X      return 0;
  25895. X    }
  25896. X
  25897. X  /* Something went wrong.  Close down and go home.  */
  25898. X
  25899. X  signal (SIGPIPE, pipe_handler);
  25900. X  _rmt_shutdown (fildes);
  25901. X  errno = EIO;
  25902. X  return -1;
  25903. X}
  25904. X
  25905. X/* Read and return the status from remote tape connection FILDES.
  25906. X   If an error occurred, return -1 and set errno.  */
  25907. X
  25908. Xstatic int
  25909. Xstatus (fildes)
  25910. X     int fildes;
  25911. X{
  25912. X  int i;
  25913. X  char c, *cp;
  25914. X  char buffer[CMDBUFSIZE];
  25915. X
  25916. X  /* Read the reply command line.  */
  25917. X
  25918. X  for (i = 0, cp = buffer; i < CMDBUFSIZE; i++, cp++)
  25919. X    {
  25920. X      if (read (READ (fildes), cp, 1) != 1)
  25921. X    {
  25922. X      _rmt_shutdown (fildes);
  25923. X      errno = EIO;
  25924. X      return -1;
  25925. X    }
  25926. X      if (*cp == '\n')
  25927. X    {
  25928. X      *cp = '\0';
  25929. X      break;
  25930. X    }
  25931. X    }
  25932. X
  25933. X  if (i == CMDBUFSIZE)
  25934. X    {
  25935. X      _rmt_shutdown (fildes);
  25936. X      errno = EIO;
  25937. X      return -1;
  25938. X    }
  25939. X
  25940. X  /* Check the return status.  */
  25941. X
  25942. X  for (cp = buffer; *cp; cp++)
  25943. X    if (*cp != ' ')
  25944. X      break;
  25945. X
  25946. X  if (*cp == 'E' || *cp == 'F')
  25947. X    {
  25948. X      errno = atoi (cp + 1);
  25949. X      /* Skip the error message line.  */
  25950. X      while (read (READ (fildes), &c, 1) == 1)
  25951. X    if (c == '\n')
  25952. X      break;
  25953. X
  25954. X      if (*cp == 'F')
  25955. X    _rmt_shutdown (fildes);
  25956. X
  25957. X      return -1;
  25958. X    }
  25959. X
  25960. X  /* Check for mis-synced pipes. */
  25961. X
  25962. X  if (*cp != 'A')
  25963. X    {
  25964. X      _rmt_shutdown (fildes);
  25965. X      errno = EIO;
  25966. X      return -1;
  25967. X    }
  25968. X
  25969. X  /* Got an `A' (success) response.  */
  25970. X  return atoi (cp + 1);
  25971. X}
  25972. X
  25973. X#ifdef HAVE_NETDB_H
  25974. X/* Execute /etc/rmt as user USER on remote system HOST using rexec.
  25975. X   Return a file descriptor of a bidirectional socket for stdin and stdout.
  25976. X   If USER is NULL, or an empty string, use the current username.
  25977. X
  25978. X   By default, this code is not used, since it requires that
  25979. X   the user have a .netrc file in his/her home directory, or that the
  25980. X   application designer be willing to have rexec prompt for login and
  25981. X   password info.  This may be unacceptable, and .rhosts files for use
  25982. X   with rsh are much more common on BSD systems.  */
  25983. X
  25984. Xstatic int
  25985. X_rmt_rexec (host, user)
  25986. X     char *host;
  25987. X     char *user;
  25988. X{
  25989. X  struct servent *rexecserv;
  25990. X  int save_stdin = dup (fileno (stdin));
  25991. X  int save_stdout = dup (fileno (stdout));
  25992. X  int tape_fd;            /* Return value. */
  25993. X
  25994. X  /* When using cpio -o < filename, stdin is no longer the tty.
  25995. X     But the rexec subroutine reads the login and the passwd on stdin,
  25996. X     to allow remote execution of the command.
  25997. X     So, reopen stdin and stdout on /dev/tty before the rexec and
  25998. X     give them back their original value after.  */
  25999. X  if (freopen ("/dev/tty", "r", stdin) == NULL)
  26000. X    freopen ("/dev/null", "r", stdin);
  26001. X  if (freopen ("/dev/tty", "w", stdout) == NULL)
  26002. X    freopen ("/dev/null", "w", stdout);
  26003. X
  26004. X  rexecserv = getservbyname ("exec", "tcp");
  26005. X  if (NULL == rexecserv)
  26006. X    {
  26007. X      fprintf (stderr, "exec/tcp: service not available");
  26008. X      exit (1);
  26009. X    }
  26010. X  if (user != NULL && *user == '\0')
  26011. X    user = NULL;
  26012. X  tape_fd = rexec (&host, rexecserv->s_port, user, NULL,
  26013. X           "/etc/rmt", (int *) NULL);
  26014. X  fclose (stdin);
  26015. X  fdopen (save_stdin, "r");
  26016. X  fclose (stdout);
  26017. X  fdopen (save_stdout, "w");
  26018. X
  26019. X  return tape_fd;
  26020. X}
  26021. X
  26022. X#endif /* HAVE_NETDB_H */
  26023. X
  26024. X/* Open a magtape device on the system specified in PATH, as the given user.
  26025. X   PATH has the form `[user@]system:/dev/????'.
  26026. X   If COMPAT is defined, it can also have the form `system[.user]:/dev/????'.
  26027. X
  26028. X   OFLAG is O_RDONLY, O_WRONLY, etc.
  26029. X   MODE is ignored; 0666 is always used.
  26030. X
  26031. X   If successful, return the remote tape pipe number plus BIAS.
  26032. X   On error, return -1.  */
  26033. X
  26034. Xint
  26035. X__rmt_open (path, oflag, mode, bias)
  26036. X     char *path;
  26037. X     int oflag;
  26038. X     int mode;
  26039. X     int bias;
  26040. X{
  26041. X  int i, rc;
  26042. X  char buffer[CMDBUFSIZE];    /* Command buffer.  */
  26043. X  char system[MAXHOSTLEN];    /* The remote host name.  */
  26044. X  char device[CMDBUFSIZE];    /* The remote device name.  */
  26045. X  char login[CMDBUFSIZE];    /* The remote user name.  */
  26046. X  char *sys, *dev, *user;    /* For copying into the above buffers.  */
  26047. X
  26048. X  sys = system;
  26049. X  dev = device;
  26050. X  user = login;
  26051. X
  26052. X  /* Find an unused pair of file descriptors.  */
  26053. X
  26054. X  for (i = 0; i < MAXUNIT; i++)
  26055. X    if (READ (i) == -1 && WRITE (i) == -1)
  26056. X      break;
  26057. X
  26058. X  if (i == MAXUNIT)
  26059. X    {
  26060. X      errno = EMFILE;
  26061. X      return -1;
  26062. X    }
  26063. X
  26064. X  /* Pull apart the system and device, and optional user.
  26065. X     Don't munge the original string.  */
  26066. X
  26067. X  while (*path != '@'
  26068. X#ifdef COMPAT
  26069. X     && *path != '.'
  26070. X#endif
  26071. X     && *path != ':')
  26072. X    {
  26073. X      *sys++ = *path++;
  26074. X    }
  26075. X  *sys = '\0';
  26076. X  path++;
  26077. X
  26078. X  if (*(path - 1) == '@')
  26079. X    {
  26080. X      /* Saw user part of user@host.  Start over. */
  26081. X      strcpy (user, system);
  26082. X      sys = system;
  26083. X      while (*path != ':')
  26084. X    {
  26085. X      *sys++ = *path++;
  26086. X    }
  26087. X      *sys = '\0';
  26088. X      path++;
  26089. X    }
  26090. X#ifdef COMPAT
  26091. X  else if (*(path - 1) == '.')
  26092. X    {
  26093. X      while (*path != ':')
  26094. X    {
  26095. X      *user++ = *path++;
  26096. X    }
  26097. X      *user = '\0';
  26098. X      path++;
  26099. X    }
  26100. X#endif
  26101. X  else
  26102. X    *user = '\0';
  26103. X
  26104. X  while (*path)
  26105. X    {
  26106. X      *dev++ = *path++;
  26107. X    }
  26108. X  *dev = '\0';
  26109. X
  26110. X#ifdef HAVE_NETDB_H
  26111. X  /* Execute the remote command using rexec.  */
  26112. X  READ (i) = WRITE (i) = _rmt_rexec (system, login);
  26113. X  if (READ (i) < 0)
  26114. X    return -1;
  26115. X#else /* !HAVE_NETDB_H */
  26116. X  /* Set up the pipes for the `rsh' command, and fork.  */
  26117. X
  26118. X  if (pipe (to_rmt[i]) == -1 || pipe (from_rmt[i]) == -1)
  26119. X    return -1;
  26120. X
  26121. X  rc = fork ();
  26122. X  if (rc == -1)
  26123. X    return -1;
  26124. X
  26125. X  if (rc == 0)
  26126. X    {
  26127. X      /* Child.  */
  26128. X      close (0);
  26129. X      dup (to_rmt[i][0]);
  26130. X      close (to_rmt[i][0]);
  26131. X      close (to_rmt[i][1]);
  26132. X
  26133. X      close (1);
  26134. X      dup (from_rmt[i][1]);
  26135. X      close (from_rmt[i][0]);
  26136. X      close (from_rmt[i][1]);
  26137. X
  26138. X      setuid (getuid ());
  26139. X      setgid (getgid ());
  26140. X
  26141. X      if (*login)
  26142. X    {
  26143. X      execl ("/usr/ucb/rsh", "rsh", system, "-l", login,
  26144. X         "/etc/rmt", (char *) 0);
  26145. X      execl ("/usr/bin/remsh", "remsh", system, "-l", login,
  26146. X         "/etc/rmt", (char *) 0);
  26147. X      execl ("/usr/bin/rsh", "rsh", system, "-l", login,
  26148. X         "/etc/rmt", (char *) 0);
  26149. X      execl ("/usr/bsd/rsh", "rsh", system, "-l", login,
  26150. X         "/etc/rmt", (char *) 0);
  26151. X      execl ("/usr/bin/nsh", "nsh", system, "-l", login,
  26152. X         "/etc/rmt", (char *) 0);
  26153. X    }
  26154. X      else
  26155. X    {
  26156. X      execl ("/usr/ucb/rsh", "rsh", system,
  26157. X         "/etc/rmt", (char *) 0);
  26158. X      execl ("/usr/bin/remsh", "remsh", system,
  26159. X         "/etc/rmt", (char *) 0);
  26160. X      execl ("/usr/bin/rsh", "rsh", system,
  26161. X         "/etc/rmt", (char *) 0);
  26162. X      execl ("/usr/bsd/rsh", "rsh", system,
  26163. X         "/etc/rmt", (char *) 0);
  26164. X      execl ("/usr/bin/nsh", "nsh", system,
  26165. X         "/etc/rmt", (char *) 0);
  26166. X    }
  26167. X
  26168. X      /* Bad problems if we get here.  */
  26169. X
  26170. X      perror ("cannot execute remote shell");
  26171. X      _exit (1);
  26172. X    }
  26173. X
  26174. X  /* Parent.  */
  26175. X  close (to_rmt[i][0]);
  26176. X  close (from_rmt[i][1]);
  26177. X#endif /* !HAVE_NETDB_H */
  26178. X
  26179. X  /* Attempt to open the tape device.  */
  26180. X
  26181. X  sprintf (buffer, "O%s\n%d\n", device, oflag);
  26182. X  if (command (i, buffer) == -1 || status (i) == -1)
  26183. X    return -1;
  26184. X
  26185. X  return i + bias;
  26186. X}
  26187. X
  26188. X/* Close remote tape connection FILDES and shut down.
  26189. X   Return 0 if successful, -1 on error.  */
  26190. X
  26191. Xint
  26192. X__rmt_close (fildes)
  26193. X     int fildes;
  26194. X{
  26195. X  int rc;
  26196. X
  26197. X  if (command (fildes, "C\n") == -1)
  26198. X    return -1;
  26199. X
  26200. X  rc = status (fildes);
  26201. X  _rmt_shutdown (fildes);
  26202. X  return rc;
  26203. X}
  26204. X
  26205. X/* Read up to NBYTE bytes into BUF from remote tape connection FILDES.
  26206. X   Return the number of bytes read on success, -1 on error.  */
  26207. X
  26208. Xint
  26209. X__rmt_read (fildes, buf, nbyte)
  26210. X     int fildes;
  26211. X     char *buf;
  26212. X     unsigned int nbyte;
  26213. X{
  26214. X  int rc, i;
  26215. X  char buffer[CMDBUFSIZE];
  26216. X
  26217. X  sprintf (buffer, "R%d\n", nbyte);
  26218. X  if (command (fildes, buffer) == -1 || (rc = status (fildes)) == -1)
  26219. X    return -1;
  26220. X
  26221. X  for (i = 0; i < rc; i += nbyte, buf += nbyte)
  26222. X    {
  26223. X      nbyte = read (READ (fildes), buf, rc - i);
  26224. X      if (nbyte <= 0)
  26225. X    {
  26226. X      _rmt_shutdown (fildes);
  26227. X      errno = EIO;
  26228. X      return -1;
  26229. X    }
  26230. X    }
  26231. X
  26232. X  return rc;
  26233. X}
  26234. X
  26235. X/* Write NBYTE bytes from BUF to remote tape connection FILDES.
  26236. X   Return the number of bytes written on success, -1 on error.  */
  26237. X
  26238. Xint
  26239. X__rmt_write (fildes, buf, nbyte)
  26240. X     int fildes;
  26241. X     char *buf;
  26242. X     unsigned int nbyte;
  26243. X{
  26244. X  char buffer[CMDBUFSIZE];
  26245. X  RETSIGTYPE (*pipe_handler) ();
  26246. X
  26247. X  sprintf (buffer, "W%d\n", nbyte);
  26248. X  if (command (fildes, buffer) == -1)
  26249. X    return -1;
  26250. X
  26251. X  pipe_handler = signal (SIGPIPE, SIG_IGN);
  26252. X  if (write (WRITE (fildes), buf, nbyte) == nbyte)
  26253. X    {
  26254. X      signal (SIGPIPE, pipe_handler);
  26255. X      return status (fildes);
  26256. X    }
  26257. X
  26258. X  /* Write error.  */
  26259. X  signal (SIGPIPE, pipe_handler);
  26260. X  _rmt_shutdown (fildes);
  26261. X  errno = EIO;
  26262. X  return -1;
  26263. X}
  26264. X
  26265. X/* Perform an imitation lseek operation on remote tape connection FILDES.
  26266. X   Return the new file offset if successful, -1 if on error.  */
  26267. X
  26268. Xlong
  26269. X__rmt_lseek (fildes, offset, whence)
  26270. X     int fildes;
  26271. X     long offset;
  26272. X     int whence;
  26273. X{
  26274. X  char buffer[CMDBUFSIZE];
  26275. X
  26276. X  sprintf (buffer, "L%ld\n%d\n", offset, whence);
  26277. X  if (command (fildes, buffer) == -1)
  26278. X    return -1;
  26279. X
  26280. X  return status (fildes);
  26281. X}
  26282. X
  26283. X/* Perform a raw tape operation on remote tape connection FILDES.
  26284. X   Return the results of the ioctl, or -1 on error.  */
  26285. X
  26286. X#ifdef MTIOCTOP
  26287. Xint
  26288. X__rmt_ioctl (fildes, op, arg)
  26289. X     int fildes, op;
  26290. X     char *arg;
  26291. X{
  26292. X  char c;
  26293. X  int rc, cnt;
  26294. X  char buffer[CMDBUFSIZE];
  26295. X
  26296. X  switch (op)
  26297. X    {
  26298. X    default:
  26299. X      errno = EINVAL;
  26300. X      return -1;
  26301. X
  26302. X    case MTIOCTOP:
  26303. X      /* MTIOCTOP is the easy one.  Nothing is transfered in binary.  */
  26304. X      sprintf (buffer, "I%d\n%d\n", ((struct mtop *) arg)->mt_op,
  26305. X           ((struct mtop *) arg)->mt_count);
  26306. X      if (command (fildes, buffer) == -1)
  26307. X    return -1;
  26308. X      return status (fildes);    /* Return the count.  */
  26309. X
  26310. X    case MTIOCGET:
  26311. X      /* Grab the status and read it directly into the structure.
  26312. X     This assumes that the status buffer is not padded
  26313. X     and that 2 shorts fit in a long without any word
  26314. X     alignment problems; i.e., the whole struct is contiguous.
  26315. X     NOTE - this is probably NOT a good assumption.  */
  26316. X
  26317. X      if (command (fildes, "S") == -1 || (rc = status (fildes)) == -1)
  26318. X    return -1;
  26319. X
  26320. X      for (; rc > 0; rc -= cnt, arg += cnt)
  26321. X    {
  26322. X      cnt = read (READ (fildes), arg, rc);
  26323. X      if (cnt <= 0)
  26324. X        {
  26325. X          _rmt_shutdown (fildes);
  26326. X          errno = EIO;
  26327. X          return -1;
  26328. X        }
  26329. X    }
  26330. X
  26331. X      /* Check for byte position.  mt_type is a small integer field
  26332. X     (normally) so we will check its magnitude.  If it is larger than
  26333. X     256, we will assume that the bytes are swapped and go through
  26334. X     and reverse all the bytes.  */
  26335. X
  26336. X      if (((struct mtget *) arg)->mt_type < 256)
  26337. X    return 0;
  26338. X
  26339. X      for (cnt = 0; cnt < rc; cnt += 2)
  26340. X    {
  26341. X      c = arg[cnt];
  26342. X      arg[cnt] = arg[cnt + 1];
  26343. X      arg[cnt + 1] = c;
  26344. X    }
  26345. X
  26346. X      return 0;
  26347. X    }
  26348. X}
  26349. X
  26350. X#endif
  26351. END_OF_FILE
  26352. if test 14007 -ne `wc -c <'rtapelib.c'`; then
  26353.     echo shar: \"'rtapelib.c'\" unpacked with wrong size!
  26354. fi
  26355. # end of 'rtapelib.c'
  26356. fi
  26357. if test -f 'msd_dir.h' -a "${1}" != "-c" ; then 
  26358.   echo shar: Will not clobber existing file \"'msd_dir.h'\"
  26359. else
  26360. echo shar: Extracting \"'msd_dir.h'\" \(1060 characters\)
  26361. sed "s/^X//" >'msd_dir.h' <<'END_OF_FILE'
  26362. X/*
  26363. X * @(#)msd_dir.h 1.4 87/11/06    Public Domain.
  26364. X *
  26365. X *  A public domain implementation of BSD directory routines for
  26366. X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  26367. X *  August 1897
  26368. X */
  26369. X
  26370. X#define    rewinddir(dirp)    seekdir(dirp, 0L)
  26371. X
  26372. X#define    MAXNAMLEN    12
  26373. X
  26374. X#ifdef __TURBOC__
  26375. Xtypedef int ino_t;
  26376. Xtypedef int dev_t;
  26377. X#endif
  26378. X
  26379. Xstruct dirent
  26380. X  {
  26381. X    ino_t d_ino;        /* a bit of a farce */
  26382. X    int d_reclen;        /* more farce */
  26383. X    int d_namlen;        /* length of d_name */
  26384. X    char d_name[MAXNAMLEN + 1];    /* garentee null termination */
  26385. X  };
  26386. X
  26387. Xstruct _dircontents
  26388. X  {
  26389. X    char *_d_entry;
  26390. X    struct _dircontents *_d_next;
  26391. X  };
  26392. X
  26393. Xtypedef struct _dirdesc
  26394. X  {
  26395. X    int dd_id;            /* uniquely identify each open directory */
  26396. X    long dd_loc;        /* where we are in directory entry is this */
  26397. X    struct _dircontents *dd_contents;    /* pointer to contents of dir */
  26398. X    struct _dircontents *dd_cp;    /* pointer to current position */
  26399. X  } DIR;
  26400. X
  26401. Xextern DIR *opendir ();
  26402. Xextern struct dirent *readdir ();
  26403. Xextern void seekdir ();
  26404. Xextern long telldir ();
  26405. Xextern void closedir ();
  26406. END_OF_FILE
  26407. if test 1060 -ne `wc -c <'msd_dir.h'`; then
  26408.     echo shar: \"'msd_dir.h'\" unpacked with wrong size!
  26409. fi
  26410. # end of 'msd_dir.h'
  26411. fi
  26412. if test -f 'msd_dir.c' -a "${1}" != "-c" ; then 
  26413.   echo shar: Will not clobber existing file \"'msd_dir.c'\"
  26414. else
  26415. echo shar: Extracting \"'msd_dir.c'\" \(4500 characters\)
  26416. sed "s/^X//" >'msd_dir.c' <<'END_OF_FILE'
  26417. X/*
  26418. X * @(#)msd_dir.c 1.4 87/11/06    Public Domain.
  26419. X *
  26420. X *  A public domain implementation of BSD directory routines for
  26421. X *  MS-DOS.  Written by Michael Rendell ({uunet,utai}michael@garfield),
  26422. X *  August 1897
  26423. X */
  26424. X
  26425. X#include    <sys/types.h>
  26426. X#include    <sys/stat.h>
  26427. X#include    "msd_dir.h"
  26428. X#ifndef __TURBOC__
  26429. X#include    <malloc.h>
  26430. X#else
  26431. X#include    <stdlib.h>
  26432. X#endif
  26433. X#include    <string.h>
  26434. X#include    <dos.h>
  26435. X
  26436. X#ifndef    NULL
  26437. X# define    NULL    0
  26438. X#endif /* NULL */
  26439. X
  26440. X#ifndef    MAXPATHLEN
  26441. X# define    MAXPATHLEN    255
  26442. X#endif /* MAXPATHLEN */
  26443. X
  26444. X/* attribute stuff */
  26445. X#define    A_RONLY        0x01
  26446. X#define    A_HIDDEN    0x02
  26447. X#define    A_SYSTEM    0x04
  26448. X#define    A_LABEL        0x08
  26449. X#define    A_DIR        0x10
  26450. X#define    A_ARCHIVE    0x20
  26451. X
  26452. X/* dos call values */
  26453. X#define    DOSI_FINDF    0x4e
  26454. X#define    DOSI_FINDN    0x4f
  26455. X#define    DOSI_SDTA    0x1a
  26456. X
  26457. X#define    Newisnull(a, t)        ((a = (t *) malloc(sizeof(t))) == (t *) NULL)
  26458. X/* #define    ATTRIBUTES        (A_DIR | A_HIDDEN | A_SYSTEM) */
  26459. X#define ATTRIBUTES    (A_RONLY | A_SYSTEM | A_DIR)
  26460. X
  26461. X/* what find first/next calls look use */
  26462. Xtypedef struct
  26463. X  {
  26464. X    char d_buf[21];
  26465. X    char d_attribute;
  26466. X    unsigned short d_time;
  26467. X    unsigned short d_date;
  26468. X    long d_size;
  26469. X    char d_name[13];
  26470. X  }
  26471. X
  26472. XDta_buf;
  26473. X
  26474. Xstatic char *getdirent ();
  26475. Xstatic void mysetdta ();
  26476. Xstatic void free_dircontents ();
  26477. X
  26478. Xstatic Dta_buf dtabuf;
  26479. Xstatic Dta_buf *dtapnt = &dtabuf;
  26480. Xstatic union REGS reg, nreg;
  26481. X
  26482. X#if    defined(M_I86LM)
  26483. Xstatic struct SREGS sreg;
  26484. X#endif
  26485. X
  26486. XDIR *
  26487. Xopendir (name)
  26488. X     char *name;
  26489. X{
  26490. X  struct stat statb;
  26491. X  DIR *dirp;
  26492. X  char c;
  26493. X  char *s;
  26494. X  struct _dircontents *dp;
  26495. X  char nbuf[MAXPATHLEN + 1];
  26496. X
  26497. X  if (stat (name, &statb) < 0 || (statb.st_mode & S_IFMT) != S_IFDIR)
  26498. X    return (DIR *) NULL;
  26499. X  if (Newisnull (dirp, DIR))
  26500. X    return (DIR *) NULL;
  26501. X  if (*name && (c = name[strlen (name) - 1]) != '\\' && c != '/')
  26502. X    (void) strcat (strcpy (nbuf, name), "\\*.*");
  26503. X  else
  26504. X    (void) strcat (strcpy (nbuf, name), "*.*");
  26505. X  dirp->dd_loc = 0;
  26506. X  mysetdta ();
  26507. X  dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) NULL;
  26508. X  if ((s = getdirent (nbuf)) == (char *) NULL)
  26509. X    return dirp;
  26510. X  do
  26511. X    {
  26512. X      if (Newisnull (dp, struct _dircontents) || (dp->_d_entry =
  26513. X             malloc ((unsigned) (strlen (s) + 1))) == (char *) NULL)
  26514. X    {
  26515. X      if (dp)
  26516. X        free ((char *) dp);
  26517. X      free_dircontents (dirp->dd_contents);
  26518. X      return (DIR *) NULL;
  26519. X    }
  26520. X      if (dirp->dd_contents)
  26521. X    dirp->dd_cp = dirp->dd_cp->_d_next = dp;
  26522. X      else
  26523. X    dirp->dd_contents = dirp->dd_cp = dp;
  26524. X      (void) strcpy (dp->_d_entry, s);
  26525. X      dp->_d_next = (struct _dircontents *) NULL;
  26526. X    }
  26527. X  while ((s = getdirent ((char *) NULL)) != (char *) NULL);
  26528. X  dirp->dd_cp = dirp->dd_contents;
  26529. X
  26530. X  return dirp;
  26531. X}
  26532. X
  26533. Xvoid
  26534. Xclosedir (dirp)
  26535. X     DIR *dirp;
  26536. X{
  26537. X  free_dircontents (dirp->dd_contents);
  26538. X  free ((char *) dirp);
  26539. X}
  26540. X
  26541. Xstruct dirent *
  26542. Xreaddir (dirp)
  26543. X     DIR *dirp;
  26544. X{
  26545. X  static struct dirent dp;
  26546. X
  26547. X  if (dirp->dd_cp == (struct _dircontents *) NULL)
  26548. X    return (struct dirent *) NULL;
  26549. X  dp.d_namlen = dp.d_reclen =
  26550. X    strlen (strcpy (dp.d_name, dirp->dd_cp->_d_entry));
  26551. X  strlwr (dp.d_name);        /* JF */
  26552. X  dp.d_ino = 0;
  26553. X  dirp->dd_cp = dirp->dd_cp->_d_next;
  26554. X  dirp->dd_loc++;
  26555. X
  26556. X  return &dp;
  26557. X}
  26558. X
  26559. Xvoid
  26560. Xseekdir (dirp, off)
  26561. X     DIR *dirp;
  26562. X     long off;
  26563. X{
  26564. X  long i = off;
  26565. X  struct _dircontents *dp;
  26566. X
  26567. X  if (off < 0)
  26568. X    return;
  26569. X  for (dp = dirp->dd_contents; --i >= 0 && dp; dp = dp->_d_next)
  26570. X    ;
  26571. X  dirp->dd_loc = off - (i + 1);
  26572. X  dirp->dd_cp = dp;
  26573. X}
  26574. X
  26575. Xlong
  26576. Xtelldir (dirp)
  26577. X     DIR *dirp;
  26578. X{
  26579. X  return dirp->dd_loc;
  26580. X}
  26581. X
  26582. Xstatic void
  26583. Xfree_dircontents (dp)
  26584. X     struct _dircontents *dp;
  26585. X{
  26586. X  struct _dircontents *odp;
  26587. X
  26588. X  while (dp)
  26589. X    {
  26590. X      if (dp->_d_entry)
  26591. X    free (dp->_d_entry);
  26592. X      dp = (odp = dp)->_d_next;
  26593. X      free ((char *) odp);
  26594. X    }
  26595. X}
  26596. X
  26597. Xstatic char *
  26598. Xgetdirent (dir)
  26599. X     char *dir;
  26600. X{
  26601. X  if (dir != (char *) NULL)
  26602. X    {                /* get first entry */
  26603. X      reg.h.ah = DOSI_FINDF;
  26604. X      reg.h.cl = ATTRIBUTES;
  26605. X#if    defined(M_I86LM)
  26606. X      reg.x.dx = FP_OFF (dir);
  26607. X      sreg.ds = FP_SEG (dir);
  26608. X#else
  26609. X      reg.x.dx = (unsigned) dir;
  26610. X#endif
  26611. X    }
  26612. X  else
  26613. X    {                /* get next entry */
  26614. X      reg.h.ah = DOSI_FINDN;
  26615. X#if    defined(M_I86LM)
  26616. X      reg.x.dx = FP_OFF (dtapnt);
  26617. X      sreg.ds = FP_SEG (dtapnt);
  26618. X#else
  26619. X      reg.x.dx = (unsigned) dtapnt;
  26620. X#endif
  26621. X    }
  26622. X#if    defined(M_I86LM)
  26623. X  intdosx (®, &nreg, &sreg);
  26624. X#else
  26625. X  intdos (®, &nreg);
  26626. X#endif
  26627. X  if (nreg.x.cflag)
  26628. X    return (char *) NULL;
  26629. X
  26630. X  return dtabuf.d_name;
  26631. X}
  26632. X
  26633. Xstatic void
  26634. Xmysetdta ()
  26635. X{
  26636. X  reg.h.ah = DOSI_SDTA;
  26637. X#if    defined(M_I86LM)
  26638. X  reg.x.dx = FP_OFF (dtapnt);
  26639. X  sreg.ds = FP_SEG (dtapnt);
  26640. X  intdosx (®, &nreg, &sreg);
  26641. X#else
  26642. X  reg.x.dx = (int) dtapnt;
  26643. X  intdos (®, &nreg);
  26644. X#endif
  26645. X}
  26646. END_OF_FILE
  26647. if test 4500 -ne `wc -c <'msd_dir.c'`; then
  26648.     echo shar: \"'msd_dir.c'\" unpacked with wrong size!
  26649. fi
  26650. # end of 'msd_dir.c'
  26651. fi
  26652. if test -f 'tcexparg.c' -a "${1}" != "-c" ; then 
  26653.   echo shar: Will not clobber existing file \"'tcexparg.c'\"
  26654. else
  26655. echo shar: Extracting \"'tcexparg.c'\" \(6079 characters\)
  26656. sed "s/^X//" >'tcexparg.c' <<'END_OF_FILE'
  26657. X/* tcexparg.c - Unix-style command line wildcards for Turbo C 2.0
  26658. X
  26659. X   This file is in the public domain.
  26660. X
  26661. X   Compile your main program with -Dmain=_main and link with this file.
  26662. X
  26663. X   After that, it is just as if the operating system had expanded the
  26664. X   arguments, except that they are not sorted.  The program name and all
  26665. X   arguments that are expanded from wildcards are lowercased.
  26666. X
  26667. X   Syntax for wildcards:
  26668. X   *        Matches zero or more of any character (except a '.' at
  26669. X        the beginning of a name).
  26670. X   ?        Matches any single character.
  26671. X   [r3z]    Matches 'r', '3', or 'z'.
  26672. X   [a-d]    Matches a single character in the range 'a' through 'd'.
  26673. X   [!a-d]    Matches any single character except a character in the
  26674. X        range 'a' through 'd'.
  26675. X
  26676. X   The period between the filename root and its extension need not be
  26677. X   given explicitly.  Thus, the pattern `a*e' will match 'abacus.exe'
  26678. X   and 'axyz.e' as well as 'apple'.  Comparisons are not case sensitive.
  26679. X
  26680. X   Authors:
  26681. X   The expargs code is a modification of wildcard expansion code
  26682. X   written for Turbo C 1.0 by
  26683. X   Richard Hargrove
  26684. X   Texas Instruments, Inc.
  26685. X   P.O. Box 869305, m/s 8473
  26686. X   Plano, Texas 75086
  26687. X   214/575-4128
  26688. X   and posted to USENET in September, 1987.
  26689. X
  26690. X   The wild_match code was written by Rich Salz, rsalz@bbn.com,
  26691. X   posted to net.sources in November, 1986.
  26692. X
  26693. X   The code connecting the two is by Mike Slomin, bellcore!lcuxa!mike2,
  26694. X   posted to comp.sys.ibm.pc in November, 1988.
  26695. X
  26696. X   Major performance enhancements and bug fixes, and source cleanup,
  26697. X   by David MacKenzie, djm@gnu.ai.mit.edu.  */
  26698. X
  26699. X#include <stdio.h>
  26700. X#include <string.h>
  26701. X#include <stdlib.h>
  26702. X#include <dos.h>
  26703. X#include <dir.h>
  26704. X
  26705. X/* Number of new arguments to allocate space for at a time.  */
  26706. X#define ARGS_INCREMENT 10
  26707. X
  26708. X/* The name this program was run with, for error messages.  */
  26709. Xstatic char *program_name;
  26710. X
  26711. Xstatic char **grow_argv (char **new_argv, int new_argc);
  26712. Xstatic void fatal_error (const char *message);
  26713. X
  26714. Xint wild_match (char *string, char *pattern);
  26715. Xchar *basename (char *path);
  26716. X
  26717. Xchar **expargs (int *, char **);
  26718. X
  26719. X#ifdef main
  26720. X#undef main
  26721. X#endif
  26722. X
  26723. Xint
  26724. Xmain (int argc, char **argv, char **envp)
  26725. X{
  26726. X  argv = expargs (&argc, argv);
  26727. X  return _main (argc, argv, envp);
  26728. X}
  26729. X
  26730. Xchar **
  26731. Xexpargs (int *pargc, char **argv)
  26732. X{
  26733. X  char path[MAXPATH + 1];
  26734. X  char **new_argv;
  26735. X  struct ffblk block;
  26736. X  char *path_base;
  26737. X  char *arg_base;
  26738. X  int argind;
  26739. X  int new_argc;
  26740. X  int path_length;
  26741. X  int matched;
  26742. X
  26743. X  program_name = argv[0];
  26744. X  if (program_name && *program_name)
  26745. X    strlwr (program_name);
  26746. X  new_argv = grow_argv (NULL, 0);
  26747. X  new_argv[0] = argv[0];
  26748. X  new_argc = 1;
  26749. X
  26750. X  for (argind = 1; argind < *pargc; ++argind)
  26751. X    {
  26752. X      matched = 0;
  26753. X      if (strpbrk (argv[argind], "?*[") != NULL)
  26754. X    {
  26755. X      strncpy (path, argv[argind], MAXPATH - 3);
  26756. X      path_base = basename (path);
  26757. X      strcpy (path_base, "*.*");
  26758. X      arg_base = argv[argind] + (path_base - path);
  26759. X
  26760. X      if (!findfirst (path, &block, FA_DIREC))
  26761. X        {
  26762. X          strlwr (path);
  26763. X          do
  26764. X        {
  26765. X          /* Only match "." and ".." explicitly.  */
  26766. X          if (*block.ff_name == '.' && *arg_base != '.')
  26767. X            continue;
  26768. X          path_length = stpcpy (path_base, block.ff_name) - path + 1;
  26769. X          strlwr (path_base);
  26770. X          if (wild_match (path, argv[argind]))
  26771. X            {
  26772. X              matched = 1;
  26773. X              new_argv[new_argc] = (char *) malloc (path_length);
  26774. X              if (new_argv[new_argc] == NULL)
  26775. X            fatal_error ("memory exhausted");
  26776. X              strcpy (new_argv[new_argc++], path);
  26777. X              new_argv = grow_argv (new_argv, new_argc);
  26778. X            }
  26779. X          } while (!findnext (&block));
  26780. X        }
  26781. X    }
  26782. X      if (matched == 0)
  26783. X    new_argv[new_argc++] = argv[argind];
  26784. X      new_argv = grow_argv (new_argv, new_argc);
  26785. X    }
  26786. X
  26787. X  *pargc = new_argc;
  26788. X  new_argv[new_argc] = NULL;
  26789. X  return &new_argv[0];
  26790. X}
  26791. X
  26792. X/* Return a pointer to the last element of PATH.  */
  26793. X
  26794. Xchar *
  26795. Xbasename (char *path)
  26796. X{
  26797. X  char *tail;
  26798. X
  26799. X  for (tail = path; *path; ++path)
  26800. X    if (*path == ':' || *path == '\\')
  26801. X      tail = path + 1;
  26802. X  return tail;
  26803. X}
  26804. X
  26805. Xstatic char **
  26806. Xgrow_argv (char **new_argv, int new_argc)
  26807. X{
  26808. X  if (new_argc % ARGS_INCREMENT == 0)
  26809. X    {
  26810. X      new_argv = (char **) realloc
  26811. X    (new_argv, sizeof (char *) * (new_argc + ARGS_INCREMENT));
  26812. X      if (new_argv == NULL)
  26813. X    fatal_error ("memory exhausted");
  26814. X    }
  26815. X  return new_argv;
  26816. X}
  26817. X
  26818. Xstatic void
  26819. Xfatal_error (const char *message)
  26820. X{
  26821. X  putc ('\n', stderr);
  26822. X  if (program_name && *program_name)
  26823. X    {
  26824. X      fputs (program_name, stderr);
  26825. X      fputs (": ", stderr);
  26826. X    }
  26827. X  fputs (message, stderr);
  26828. X  putc ('\n', stderr);
  26829. X  exit (1);
  26830. X}
  26831. X
  26832. X/* Shell-style pattern matching for ?, \, [], and * characters.
  26833. X   I'm putting this replacement in the public domain.
  26834. X
  26835. X   Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.  */
  26836. X
  26837. X/* The character that inverts a character class; '!' or '^'.  */
  26838. X#define INVERT '!'
  26839. X
  26840. Xstatic int star (char *string, char *pattern);
  26841. X
  26842. X/* Return nonzero if `string' matches Unix-style wildcard pattern
  26843. X   `pattern'; zero if not.  */
  26844. X
  26845. Xint
  26846. Xwild_match (char *string, char *pattern)
  26847. X{
  26848. X  int prev;        /* Previous character in character class.  */
  26849. X  int matched;        /* If 1, character class has been matched.  */
  26850. X  int reverse;        /* If 1, character class is inverted.  */
  26851. X
  26852. X  for (; *pattern; string++, pattern++)
  26853. X    switch (*pattern)
  26854. X      {
  26855. X      case '\\':
  26856. X    /* Literal match with following character; fall through.  */
  26857. X    pattern++;
  26858. X      default:
  26859. X    if (*string != *pattern)
  26860. X      return 0;
  26861. X    continue;
  26862. X      case '?':
  26863. X    /* Match anything.  */
  26864. X    if (*string == '\0')
  26865. X      return 0;
  26866. X    continue;
  26867. X      case '*':
  26868. X    /* Trailing star matches everything.  */
  26869. X    return *++pattern ? star (string, pattern) : 1;
  26870. X      case '[':
  26871. X    /* Check for inverse character class.  */
  26872. X    reverse = pattern[1] == INVERT;
  26873. X    if (reverse)
  26874. X      pattern++;
  26875. X    for (prev = 256, matched = 0; *++pattern && *pattern != ']';
  26876. X         prev = *pattern)
  26877. X      if (*pattern == '-'
  26878. X          ? *string <= *++pattern && *string >= prev
  26879. X          : *string == *pattern)
  26880. X        matched = 1;
  26881. X    if (matched == reverse)
  26882. X      return 0;
  26883. X    continue;
  26884. X      }
  26885. X
  26886. X  return *string == '\0';
  26887. X}
  26888. X
  26889. Xstatic int
  26890. Xstar (char *string, char *pattern)
  26891. X{
  26892. X  while (wild_match (string, pattern) == 0)
  26893. X    if (*++string == '\0')
  26894. X      return 0;
  26895. X  return 1;
  26896. X}
  26897. END_OF_FILE
  26898. if test 6079 -ne `wc -c <'tcexparg.c'`; then
  26899.     echo shar: \"'tcexparg.c'\" unpacked with wrong size!
  26900. fi
  26901. # end of 'tcexparg.c'
  26902. fi
  26903. if test -f 'level-0' -a "${1}" != "-c" ; then 
  26904.   echo shar: Will not clobber existing file \"'level-0'\"
  26905. else
  26906. echo shar: Extracting \"'level-0'\" \(6470 characters\)
  26907. sed "s/^X//" >'level-0' <<'END_OF_FILE'
  26908. X#!/bin/sh
  26909. X#
  26910. X# Run this script as root on the machine that has the tape drive, to make a
  26911. X# full (level-0) dump.
  26912. X#
  26913. X# If you give `now' as an argument, the dump is done immediately.
  26914. X# Otherwise, it waits until 1am, or until the hour given as argument.
  26915. X# Specify the hour as a number from 0 to 23.
  26916. X#
  26917. X# You must edit the file `backup-specs' to set the parameters for your site.
  26918. X
  26919. X# Useful for backup-specs, in case things have to be done slightly
  26920. X# differently for different dump levels. 
  26921. XDUMP_LEVEL=0
  26922. X
  26923. X# Insure `mail' is in PATH. 
  26924. XPATH="/usr/ucb:${PATH}"
  26925. Xexport PATH
  26926. X
  26927. X# This is not the most reliable test in the world.  The following might be
  26928. X# more predictable:
  26929. X#
  26930. X# whoami="`whoami`"
  26931. X# euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`"
  26932. X# if [ "${euid}" != 0 ]; then ...
  26933. X#
  26934. Xif [ ! -w / ]; then
  26935. X   echo "The backup must be run as root or else some files will fail to be dumped."
  26936. X   exit 1
  26937. Xfi
  26938. X
  26939. X# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
  26940. X. ./backup-specs
  26941. X
  26942. X# Maybe sleep until around specified or default hour.
  26943. Xif [ "${1}" != "now" ]; then
  26944. X   if [ "${1}x" != "x" ]; then
  26945. X      spec="${1}"
  26946. X   else
  26947. X      spec="${BACKUP_HOUR}"
  26948. X   fi
  26949. X
  26950. X   pausetime="`date | awk '
  26951. X     {
  26952. X      hr = substr($4, 1, 2);
  26953. X      mn = substr($4, 4, 2);
  26954. X      if((hr + 0) < (spec + 0))
  26955. X         print 3600 * (spec - hr) - 60 * mn;
  26956. X      else
  26957. X         print 3600 * (spec + (24 - hr)) - 60 * mn; 
  26958. X     }' spec=\"${spec}\"`"
  26959. X
  26960. X   clear
  26961. X   echo "${SLEEP_MESSAGE}"
  26962. X   sleep "${pausetime}"
  26963. Xfi
  26964. X
  26965. X# start doing things
  26966. X
  26967. X# Put startdate in the subject line of mailed report, since if it happens
  26968. X# to run longer than 24 hours (as may be the case if someone forgets to put
  26969. X# in the next volume of the tape in adequate time), the backup date won't
  26970. X# appear too misleading. 
  26971. Xstartdate="`date`"
  26972. X
  26973. Xhere="`pwd`"
  26974. X
  26975. X# Logfile name should be in the form  ``log-1993-03-18-level-0''
  26976. X# i.e. year-month-date.  This format is useful for sorting by name, since
  26977. X# logfiles are intentionally kept online for future reference.
  26978. XLOGFILE="log-`date | sed -ne '
  26979. X   s/[^ ]*  *\([^ ]*\)  *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
  26980. X   /-[0-9]$/s/\([0-9]\)$/0\1/
  26981. X   /Jan/{s/Jan/01/p;q;}
  26982. X   /Feb/{s/Feb/02/p;q;}
  26983. X   /Mar/{s/Mar/03/p;q;}
  26984. X   /Apr/{s/Apr/04/p;q;}
  26985. X   /May/{s/May/05/p;q;}
  26986. X   /Jun/{s/Jun/06/p;q;}
  26987. X   /Jul/{s/Jul/07/p;q;}
  26988. X   /Aug/{s/Aug/08/p;q;}
  26989. X   /Sep/{s/Sep/09/p;q;}
  26990. X   /Oct/{s/Oct/10/p;q;}
  26991. X   /Nov/{s/Nov/11/p;q;}
  26992. X   /Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}"
  26993. X
  26994. Xlocalhost="`hostname | sed -e 's/\..*//'`"
  26995. X
  26996. XTAR_PART1="${TAR} -c --multi-volume --one-file-system --block-size=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}"
  26997. X
  26998. X# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
  26999. Xif [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
  27000. X   TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
  27001. Xfi
  27002. X
  27003. X# Make sure the log file did not already exist.  Create it.
  27004. X
  27005. Xif [ -f "${LOGFILE}" ] ; then
  27006. X   echo "Log file ${LOGFILE} already exists." 1>&2
  27007. X   exit 1
  27008. Xelse
  27009. X   touch "${LOGFILE}"
  27010. Xfi
  27011. X
  27012. X# Most everything below here is run in a subshell for which all output is
  27013. X# piped through `tee' to the logfile.  Doing this, instead of having
  27014. X# multiple pipelines all over the place, is cleaner and allows access to
  27015. X# the exit value from various commands more easily. 
  27016. X(
  27017. X # Caveat: Some version of `mt' require `-t', not `-f'. 
  27018. X mt -f "${TAPE_FILE}" rewind
  27019. X rm -f "${VOLNO_FILE}"
  27020. X
  27021. X set - ${BACKUP_DIRS}
  27022. X while [ $# -ne 0 ] ; do
  27023. X    date="`date`"
  27024. X    remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`"
  27025. X    fs="`echo \"${1}\" | sed -e 's/^.*://'`"
  27026. X    fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
  27027. X
  27028. X    # This filename must be absolute; it is opened on the machine that runs tar.
  27029. X    TAR_PART2="--listed=/etc/tar-backup/temp.level-0"
  27030. X    TAR_PART3="--label='Full backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ."
  27031. X
  27032. X    echo "Backing up ${1} at ${date}"
  27033. X
  27034. X    # Actually back things up.
  27035. X
  27036. X    if [ "z${localhost}" != "z${remotehost}" ] ; then
  27037. X       rsh "${remotehost}" mkdir /etc/tar-backup > /dev/null 2>&1
  27038. X       rsh "${remotehost}" rm -f /etc/tar-backup/temp.level-0
  27039. X       rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3}
  27040. X    else
  27041. X       mkdir /etc/tar-backup > /dev/null 2>&1
  27042. X       rm -f /etc/tar-backup/temp.level-0
  27043. X       # Using `sh -c exec' causes nested quoting and shell substitution
  27044. X       # to be handled here in the same way rsh handles it.
  27045. X       sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}"
  27046. X    fi
  27047. X
  27048. X    # `rsh' doesn't exit with the exit status of the remote command.  What
  27049. X    # stupid lossage.  TODO: think of a reliable workaround. 
  27050. X    if [ $? -ne 0 ] ; then
  27051. X       echo "Backup of ${1} failed." 1>&2
  27052. X       # I'm assuming that the tar will have written an empty
  27053. X       # file to the tape, otherwise I should do a cat here.
  27054. X    else
  27055. X       if [ "z${localhost}" != "z${remotehost}" ] ; then
  27056. X         rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0"
  27057. X       else
  27058. X         mv -f /etc/tar-backup/temp.level-0 "/etc/tar-backup/${fsname}.level-0"
  27059. X       fi
  27060. X    fi
  27061. X    ${TAPE_STATUS}
  27062. X    sleep 60
  27063. X    shift
  27064. X done
  27065. X
  27066. X # Dump any individual files requested.
  27067. X
  27068. X if [ "x${BACKUP_FILES}" != "x" ] ; then
  27069. X    date="`date`"
  27070. X
  27071. X    TAR_PART2="--listed=/etc/tar-backup/temp.level-0"
  27072. X    TAR_PART3="--label='Full backup of miscellaneous files at ${date}'"
  27073. X
  27074. X    mkdir /etc/tar-backup > /dev/null 2>&1
  27075. X    rm -f /etc/tar-backup/temp.level-0
  27076. X
  27077. X    echo "Backing up miscellaneous files at ${date}"
  27078. X
  27079. X    # Using `sh -c exec' causes nested quoting and shell substitution
  27080. X    # to be handled here in the same way rsh handles it.
  27081. X    sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}"
  27082. X
  27083. X    # `rsh' doesn't exit with the exit status of the remote command.  What
  27084. X    # lossage.  TODO: think of a reliable workaround. 
  27085. X    if [ $? -ne 0 ] ; then
  27086. X      echo "Backup of miscellaneous files failed."
  27087. X      # I'm assuming that the tar will have written an empty
  27088. X      # file to the tape, otherwise I should do a cat here.
  27089. X    else
  27090. X      mv -f /etc/tar-backup/temp.level-0 /etc/tar-backup/misc.level-0
  27091. X    fi
  27092. X    ${TAPE_STATUS}
  27093. X else
  27094. X    echo "No miscellaneous files specified"
  27095. X fi
  27096. X
  27097. X # Caveat: some versions of `mt' use `-t' instead of `-f'.
  27098. X mt -f "${TAPE_FILE}" rewind
  27099. X mt -f "${TAPE_FILE}" offl
  27100. X
  27101. X) 2>&1 | tee -a "${LOGFILE}"
  27102. X
  27103. Xecho "Sending the dump log to ${ADMINISTRATOR}"
  27104. Xmail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
  27105. X
  27106. X# eof
  27107. END_OF_FILE
  27108. if test 6470 -ne `wc -c <'level-0'`; then
  27109.     echo shar: \"'level-0'\" unpacked with wrong size!
  27110. fi
  27111. chmod +x 'level-0'
  27112. # end of 'level-0'
  27113. fi
  27114. if test -f 'level-1' -a "${1}" != "-c" ; then 
  27115.   echo shar: Will not clobber existing file \"'level-1'\"
  27116. else
  27117. echo shar: Extracting \"'level-1'\" \(6590 characters\)
  27118. sed "s/^X//" >'level-1' <<'END_OF_FILE'
  27119. X#!/bin/sh 
  27120. X#
  27121. X# Run this script as root on the machine that has the tape drive, to make a
  27122. X# level-1 dump containing all files changed since the last full dump.
  27123. X#
  27124. X# If you give `now' as an argument, the dump is done immediately.
  27125. X# Otherwise, it waits until 1am.
  27126. X#
  27127. X# You must edit the file `backup-specs' to set the parameters for your site.
  27128. X
  27129. X# Useful for backup-specs, in case things have to be done slightly
  27130. X# differently for different dump levels. 
  27131. XDUMP_LEVEL=1
  27132. X
  27133. X# Insure `mail' is in PATH. 
  27134. XPATH="/usr/ucb:${PATH}"
  27135. Xexport PATH
  27136. X
  27137. X# This is not the most reliable test in the world.  The following might be
  27138. X# more predictable:
  27139. X#
  27140. X# whoami="`whoami`"
  27141. X# euid="`sed -ne '/^'\"${whoami}\"':/{s/^[^:]*:[^:]*://;s/:.*//p;q;}' /etc/passwd`"
  27142. X# if [ "${euid}" != 0 ]; then ...
  27143. X#
  27144. Xif [ ! -w / ]; then
  27145. X   echo "The backup must be run as root or else some files will fail to be dumped."
  27146. X   exit 1
  27147. Xfi
  27148. X
  27149. X# Get the values of BACKUP_DIRS, BACKUP_FILES, and other variables.
  27150. X. ./backup-specs
  27151. X
  27152. X# Maybe sleep until around specified or default hour.
  27153. Xif [ "z${1}" != "znow" ]; then
  27154. X   if [ "${1}x" != "x" ]; then
  27155. X      spec="${1}"
  27156. X   else
  27157. X      spec="${BACKUP_HOUR}"
  27158. X   fi
  27159. X
  27160. X   pausetime="`date | awk '
  27161. X     {
  27162. X      hr = substr($4, 1, 2);
  27163. X      mn = substr($4, 4, 2);
  27164. X      if((hr + 0) < (spec + 0))
  27165. X         print 3600 * (spec - hr) - 60 * mn;
  27166. X      else
  27167. X         print 3600 * (spec + (24 - hr)) - 60 * mn; 
  27168. X     }' spec=\"${spec}\"`"
  27169. X
  27170. X   clear
  27171. X   echo "${SLEEP_MESSAGE}"
  27172. X   sleep "${pausetime}"
  27173. Xfi
  27174. X
  27175. X# start doing things
  27176. X
  27177. X# Put startdate in the subject line of mailed report, since if it happens
  27178. X# to run longer than 24 hours (as may be the case if someone forgets to put
  27179. X# in the next volume of the tape in adequate time), the backup date won't
  27180. X# appear too misleading. 
  27181. Xstartdate="`date`"
  27182. X
  27183. Xhere="`pwd`"
  27184. X
  27185. X# Logfile name should be in the form  ``log-1993-03-18-level-1''
  27186. X# i.e. year-month-date.  This format is useful for sorting by name, since
  27187. X# logfiles are intentionally kept online for future reference.
  27188. XLOGFILE="log-`date | sed -ne '
  27189. X   s/[^ ]*  *\([^ ]*\)  *\([^ ]*\).* \([^ ]*\)$/\3-\1-\2/
  27190. X   /-[0-9]$/s/\([0-9]\)$/0\1/
  27191. X   /Jan/{s/Jan/01/p;q;}
  27192. X   /Feb/{s/Feb/02/p;q;}
  27193. X   /Mar/{s/Mar/03/p;q;}
  27194. X   /Apr/{s/Apr/04/p;q;}
  27195. X   /May/{s/May/05/p;q;}
  27196. X   /Jun/{s/Jun/06/p;q;}
  27197. X   /Jul/{s/Jul/07/p;q;}
  27198. X   /Aug/{s/Aug/08/p;q;}
  27199. X   /Sep/{s/Sep/09/p;q;}
  27200. X   /Oct/{s/Oct/10/p;q;}
  27201. X   /Nov/{s/Nov/11/p;q;}
  27202. X   /Dec/{s/Dec/12/p;q;}'`-level-${DUMP_LEVEL}"
  27203. X
  27204. Xlocalhost="`hostname | sed -e 's/\..*//'`"
  27205. X
  27206. XTAR_PART1="${TAR} -c --multi-volume --one-file-system --block-size=${BLOCKING} --sparse --volno-file=${VOLNO_FILE}"
  27207. X
  27208. X# Only use --info-script if DUMP_REMIND_SCRIPT was defined in backup-specs
  27209. Xif [ "x${DUMP_REMIND_SCRIPT}" != "x" ]; then
  27210. X   TAR_PART1="${TAR_PART1} --info-script='${DUMP_REMIND_SCRIPT}'"
  27211. Xfi
  27212. X
  27213. X# Make sure the log file did not already exist.  Create it.
  27214. X
  27215. Xif [ -f "${LOGFILE}" ] ; then
  27216. X   echo "Log file ${LOGFILE} already exists." 1>&2
  27217. X   exit 1
  27218. Xelse
  27219. X   touch "${LOGFILE}"
  27220. Xfi
  27221. X
  27222. X# Most everything below here is run in a subshell for which all output is
  27223. X# piped through `tee' to the logfile.  Doing this, instead of having
  27224. X# multiple pipelines all over the place, is cleaner and allows access to
  27225. X# the exit value from various commands more easily. 
  27226. X(
  27227. X # Caveat: Some version of `mt' require `-t', not `-f'. 
  27228. X mt -f "${TAPE_FILE}" rewind
  27229. X rm -f "${VOLNO_FILE}"
  27230. X
  27231. X set - ${BACKUP_DIRS}
  27232. X while [ $# -ne 0 ] ; do
  27233. X    date="`date`"
  27234. X    remotehost="`echo \"${1}\" | sed -e 's/:.*$//'`"
  27235. X    fs="`echo \"${1}\" | sed -e 's/^.*://'`"
  27236. X    fsname="`echo \"${1}\" | sed -e 's/\//:/g'`"
  27237. X
  27238. X    # This filename must be absolute; it is opened on the machine that runs tar.
  27239. X    TAR_PART2="--listed=/etc/tar-backup/temp.level-1"
  27240. X    TAR_PART3="--label='level 1 backup of ${fs} on ${remotehost} at ${date}' -C ${fs} ."
  27241. X
  27242. X    echo "Backing up ${1} at ${date}"
  27243. X    echo "Last full dump on this filesystem:"
  27244. X
  27245. X    if [ "z${remotehost}" != "z${localhost}" ] ; then
  27246. X      rsh "${remotehost}" "ls -l /etc/tar-backup/${fsname}.level-0; \
  27247. X          cp /etc/tar-backup/${fsname}.level-0 /etc/tar-backup/temp.level-1"
  27248. X    else
  27249. X      ls -l "/etc/tar-backup/${fsname}.level-0"
  27250. X      cp "/etc/tar-backup/${fsname}.level-0" /etc/tar-backup/temp.level-1
  27251. X    fi
  27252. X
  27253. X    # Actually back things up.
  27254. X
  27255. X    if [ "z${remotehost}" != "z${localhost}" ] ; then
  27256. X       rsh "${remotehost}" ${TAR_PART1} -f "${localhost}:${TAPE_FILE}" ${TAR_PART2} ${TAR_PART3}
  27257. X    else
  27258. X       # Using `sh -c exec' causes nested quoting and shell substitution
  27259. X       # to be handled here in the same way rsh handles it.
  27260. X       sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3}"
  27261. X    fi
  27262. X
  27263. X    # `rsh' doesn't exit with the exit status of the remote command.  What
  27264. X    # stupid lossage.  TODO: think of a reliable workaround. 
  27265. X    if [ $? -ne 0 ] ; then
  27266. X       echo "Backup of ${1} failed."
  27267. X       # I'm assuming that the tar will have written an empty
  27268. X       # file to the tape, otherwise I should do a cat here.
  27269. X    else
  27270. X       if [ "z${localhost}" != "z${remotehost}" ] ; then
  27271. X         rsh "${remotehost}" mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1"
  27272. X       else
  27273. X         mv -f /etc/tar-backup/temp.level-1 "/etc/tar-backup/${fsname}.level-1"
  27274. X       fi
  27275. X    fi
  27276. X    ${TAPE_STATUS}
  27277. X    sleep 60
  27278. X    shift
  27279. X done
  27280. X
  27281. X # Dump any individual files requested.
  27282. X
  27283. X if [ "x${BACKUP_FILES}" != "x" ] ; then
  27284. X    date="`date`"
  27285. X    TAR_PART2="--listed=/etc/tar-backup/temp.level-1"
  27286. X    TAR_PART3="--label='Incremental backup of miscellaneous files at ${date}'"
  27287. X
  27288. X    echo "Backing up miscellaneous files at ${date}"
  27289. X    echo "Last full dump of these files:"
  27290. X    ls -l /etc/tar-backup/misc.level-0
  27291. X
  27292. X    rm -f /etc/tar-backup/temp.level-1
  27293. X    cp /etc/tar-backup/misc.level-0 /etc/tar-backup/temp.level-1
  27294. X
  27295. X    # Using `sh -c exec' causes nested quoting and shell substitution
  27296. X    # to be handled here in the same way rsh handles it.
  27297. X    sh -c "exec ${TAR_PART1} -f \"${TAPE_FILE}\" ${TAR_PART2} ${TAR_PART3} ${BACKUP_FILES}"
  27298. X
  27299. X    if [ $? -ne 0 ] ; then
  27300. X      echo "Backup of miscellaneous files failed." 1>&2
  27301. X      # I'm assuming that the tar will have written an empty
  27302. X      # file to the tape, otherwise I should do a cat here.
  27303. X    else
  27304. X      mv -f /etc/tar-backup/temp.level-1 /etc/tar-backup/misc.level-1
  27305. X    fi
  27306. X    ${TAPE_STATUS}
  27307. X else
  27308. X    echo "No miscellaneous files specified"
  27309. X fi
  27310. X
  27311. X # Caveat: some versions of `mt' use `-t' instead of `-f'.
  27312. X mt -f "${TAPE_FILE}" rewind
  27313. X mt -f "${TAPE_FILE}" offl
  27314. X
  27315. X) 2>&1 | tee -a "${LOGFILE}"
  27316. X
  27317. Xecho "Sending the dump log to ${ADMINISTRATOR}"
  27318. Xmail -s "Results of backup started ${startdate}" ${ADMINISTRATOR} < "${LOGFILE}"
  27319. X
  27320. X# eof
  27321. END_OF_FILE
  27322. if test 6590 -ne `wc -c <'level-1'`; then
  27323.     echo shar: \"'level-1'\" unpacked with wrong size!
  27324. fi
  27325. chmod +x 'level-1'
  27326. # end of 'level-1'
  27327. fi
  27328. if test -f 'backup-specs' -a "${1}" != "-c" ; then 
  27329.   echo shar: Will not clobber existing file \"'backup-specs'\"
  27330. else
  27331. echo shar: Extracting \"'backup-specs'\" \(2661 characters\)
  27332. sed "s/^X//" >'backup-specs' <<'END_OF_FILE'
  27333. X# site-specific parameters for file system backup.
  27334. X
  27335. X# User name of administrator of backups.
  27336. XADMINISTRATOR=backup-reports
  27337. X
  27338. X# Hour at which backups are normally done.
  27339. X# This should be a number from 0 to 23.
  27340. XBACKUP_HOUR=1
  27341. X
  27342. X# Location of GNU tar.  This must be the same for all hosts.
  27343. XTAR=/usr/local/gnubin/tar
  27344. X
  27345. X# Device to use for dumping.  It should be on the host
  27346. X# on which the dump scripts are run.
  27347. XTAPE_FILE=/dev/nrsmt0
  27348. X
  27349. X# Command to obtain status of tape drive, including error count.
  27350. X# On some tape drives there may not be such a command;
  27351. X# then simply use `TAPE_STATUS=false'.
  27352. X#
  27353. X# Might also consider
  27354. X#    TAPE_STATUS="mt -f ${TAPE_FILE} status"
  27355. X# if `mts' is missing, though this alternative is rather verbose. 
  27356. XTAPE_STATUS="mts -t ${TAPE_FILE}"
  27357. X
  27358. X# Blocking factor to use for writing the dump.
  27359. XBLOCKING=124
  27360. X
  27361. X# Name of temporary file to hold volume numbers.  This needs to be accessible
  27362. X# by all the machines which have filesystems to be dumped.
  27363. XVOLNO_FILE=/home/gd2/dump/volnofile
  27364. X
  27365. X# Script to be run when it's time to insert a new tape in for the next
  27366. X# volume.  Administrators may want to tailor this script for their site. 
  27367. X# If this variable isn't set, tar will use some default behavior which is
  27368. X# probably defined in the manual. 
  27369. X#DUMP_REMIND_SCRIPT='rsh apple-gunkies /home/gd2/dump/dump-remind'
  27370. X
  27371. X# List of file systems to be dumped.
  27372. X# Actually, any directory may be used, but if it has subdirectories on
  27373. X# other file systems, they are not included.
  27374. X# The host name specifies which host to run tar on.
  27375. X# It should normally be the host that actually has the file system.
  27376. X# If GNU tar is not installed on that machine, then you can specify some
  27377. X# other host which can access the file system through NFS.
  27378. X# Although these are arranged one per line, that is not mandatory.
  27379. X# It does not work to use # for comments within the string.
  27380. X
  27381. XBACKUP_DIRS='
  27382. X    albert:/fs/fsf
  27383. X    sugar-bombs:/fs/gd
  27384. X    albert:/fs/gd2
  27385. X    nutrimat:/fs/gp
  27386. X    nutrimat:/fs/gp2
  27387. X    albert:/fs/mailer
  27388. X    placebo:/archive
  27389. X        nutrimat:/fs/dist
  27390. X    albert:/
  27391. X    albert:/usr
  27392. X    nutrimat:/
  27393. X    placebo:/
  27394. X    ernst:/usr1
  27395. X'
  27396. X
  27397. X# List of individual files to be dumped.
  27398. X# These should be accesible from the machine on which the dump is run.
  27399. XBACKUP_FILES=''
  27400. X
  27401. X# Message to display on the terminal while waiting for dump time.  Usually
  27402. X# this will just be some literal text, preferably something more
  27403. X# entertaining than this.  The awk script here saves some redundant
  27404. X# repetition, but is not really all that desirable.
  27405. XSLEEP_MESSAGE="`awk '
  27406. X   BEGIN { 
  27407. X      for (i = 0; i < 30; i++)
  27408. X         print \"           \" \
  27409. X               \"D O    N O T   T O U C H   T H I S   T E R M I N A L !!!!!\"
  27410. X   }' /dev/null`"
  27411. X
  27412. X
  27413. X# eof
  27414. END_OF_FILE
  27415. if test 2661 -ne `wc -c <'backup-specs'`; then
  27416.     echo shar: \"'backup-specs'\" unpacked with wrong size!
  27417. fi
  27418. # end of 'backup-specs'
  27419. fi
  27420. if test -f 'dump-remind' -a "${1}" != "-c" ; then 
  27421.   echo shar: Will not clobber existing file \"'dump-remind'\"
  27422. else
  27423. echo shar: Extracting \"'dump-remind'\" \(2969 characters\)
  27424. sed "s/^X//" >'dump-remind' <<'END_OF_FILE'
  27425. X#!/bin/sh
  27426. X# This file is included in the GNU tar distribution as an example.  It is
  27427. X# not used by default unless the proper line is uncommented in backup-specs.
  27428. X# System administrators will probably want to customize this and
  27429. X# backup-specs for their site. 
  27430. X#
  27431. X# This script should be run by tar with --info-script (-F) to inform
  27432. X# interested parties that a tape for the next volume of the backup needs to
  27433. X# be put in the tape drive. 
  27434. X#
  27435. X
  27436. X# Include location of `sendmail' and GNU finger. 
  27437. XPATH="/usr/lib:/usr/local/gnubin:${PATH}"
  27438. Xexport PATH
  27439. X
  27440. X# Get definition of TAPE_FILE, VOLNO_FILE, and so on. 
  27441. X. /home/gd2/dump/backup-specs
  27442. X
  27443. Xmt -f "${TAPE_FILE}" rewind
  27444. Xmt -f "${TAPE_FILE}" offl
  27445. X
  27446. Xvolno="`cat \"${VOLNO_FILE}\" 2> /dev/null`"
  27447. Xif [ $? -ne 0 ]; then
  27448. X   volno=0
  27449. Xfi
  27450. X# Until mib fixes a bug, this needs to be incremented by one. 
  27451. Xvolno=`expr ${volno} + 1`
  27452. X
  27453. X# Get a list of people to whom to mail a request for changing the tape.
  27454. X# This egregious nightmare parses the output from GNU finger which shows
  27455. X# which users are logged into consoles (and thus in the office and capable
  27456. X# of changing tapes).
  27457. X#
  27458. X# Certain users (like `root') aren't real users, and shouldn't be notified.
  27459. X# Neither should `zippy', `elvis', etc. (on the GNU machines) since they're
  27460. X# just test accounts. 
  27461. Xrecipients="`
  27462. X    finger .clients 2> /dev/null \
  27463. X     | sed -ne '
  27464. X          1{
  27465. X            /clientstatus: file has not changed in/{
  27466. X               n;n;n;n;d
  27467. X            }
  27468. X            n;n;d
  27469. X           }
  27470. X          s/^..................................................//
  27471. X          $!{/^$/d
  27472. X             /^root?*$/d
  27473. X             /^zippy$/d
  27474. X             /^fnord$/d
  27475. X             /^elvis$/d
  27476. X             /^snurd$/d
  27477. X             H
  27478. X            }
  27479. X          ${g
  27480. X            : 1
  27481. X            s/\(\n\)\([A-Za-z0-9_][A-Za-z0-9_]*\)\(\n.*\)\2\(.*\)/\1\2\3\4/g
  27482. X            s/\n$//g
  27483. X            t 1
  27484. X            s/^\n//
  27485. X            s/\n$//g
  27486. X            s/\n/, /g
  27487. X            : 2
  27488. X            s/, ,/,/g
  27489. X            t 2
  27490. X            p
  27491. X           }'`"
  27492. X
  27493. X# Customized behavior for FSF machines, to bring attention to the fact that
  27494. X# the tape needs to be changed (who looks at the terminal?)
  27495. Xsendmail -oi -t << __EOF__
  27496. XFrom: `basename $0` (backup tape-changing reminder)
  27497. XTo: ${recipients}
  27498. XCc: ${ADMINISTRATOR}
  27499. XSubject: Backup needs new tape for volume ${volno}
  27500. XReply-To: ${ADMINISTRATOR}
  27501. X
  27502. XThis is an automated report from the backup script running on 
  27503. X`hostname`. 
  27504. X
  27505. XVolume ${volno} of the backup needs to be put in the tape drive.  Usually
  27506. Xwhoever prepared the backup leaves labeled tapes on top of the drive
  27507. Xitself.  If there aren't any more, information about where to find tapes
  27508. Xand how to label them are posted on the wall by apple-gunkies (unhelpfully
  27509. Xobscured by a bookshelf).  An online copy (which is probably more
  27510. Xup-to-date) can also be found in ~friedman/etc/fsf/backup.how.
  27511. X
  27512. X__EOF__
  27513. X
  27514. X
  27515. Xecho "Please put volume ${volno} in tape drive and press RETURN"
  27516. Xread input
  27517. Xecho "Writing volume ${volno}..."
  27518. X
  27519. Xexit 0
  27520. X
  27521. X# eof
  27522. END_OF_FILE
  27523. echo shar: 1 control character may be missing from \"'dump-remind'\"
  27524. if test 2969 -ne `wc -c <'dump-remind'`; then
  27525.     echo shar: \"'dump-remind'\" unpacked with wrong size!
  27526. fi
  27527. chmod +x 'dump-remind'
  27528. # end of 'dump-remind'
  27529. fi
  27530. if test -f 'testpad.c' -a "${1}" != "-c" ; then 
  27531.   echo shar: Will not clobber existing file \"'testpad.c'\"
  27532. else
  27533. echo shar: Extracting \"'testpad.c'\" \(1541 characters\)
  27534. sed "s/^X//" >'testpad.c' <<'END_OF_FILE'
  27535. X/* Find out if we need the pad field in the header for this machine
  27536. X   Copyright (C) 1991 Free Software Foundation
  27537. X
  27538. X   This program is free software; you can redistribute it and/or
  27539. X   modify it under the terms of the GNU General Public License as
  27540. X   published by the Free Software Foundation; either version 2, or (at
  27541. X   your option) any later version.
  27542. X
  27543. X   This program is distributed in the hope that it will be useful, but
  27544. X   WITHOUT ANY WARRANTY; without even the implied warranty of
  27545. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  27546. X   General Public License for more details.
  27547. X
  27548. X   You should have received a copy of the GNU General Public License
  27549. X   along with this program; if not, write to the Free Software
  27550. X   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  27551. X*/
  27552. X
  27553. X#include <stdio.h>
  27554. X
  27555. Xstruct inc
  27556. X{
  27557. X  char a[20];
  27558. X  char b[20];
  27559. X};
  27560. X
  27561. Xstruct test1
  27562. X{
  27563. X  char a;
  27564. X  struct inc in[5];
  27565. X};
  27566. X
  27567. Xstruct test2
  27568. X{
  27569. X  char a;
  27570. X  char b;
  27571. X  struct inc in[5];
  27572. X};
  27573. X
  27574. Xvoid
  27575. Xmain ()
  27576. X{
  27577. X  struct test1 t1;
  27578. X  struct test2 t2;
  27579. X  int t1diff, t2diff;
  27580. X  FILE *fp = fopen ("testpad.h", "w");
  27581. X
  27582. X  if (fp == 0)
  27583. X    {
  27584. X      fprintf (stderr, "testpad: cannot open ");
  27585. X      fflush (stderr);
  27586. X      perror ("testpad.h");
  27587. X      exit (1);
  27588. X    }
  27589. X
  27590. X  t1diff = (char *) &t1.in[0] - (char *) &t1;
  27591. X  t2diff = (char *) &t2.in[0] - (char *) &t2;
  27592. X
  27593. X  if (t2diff == t1diff + 1)
  27594. X    fprintf (fp, "#define NEEDPAD\n");
  27595. X  else if (t1diff != t2diff)
  27596. X    fprintf (stderr, "Cannot determine padding for tar struct, \n\
  27597. Xwill try with none.\n");
  27598. X
  27599. X  fclose (fp);
  27600. X  exit (0);
  27601. X}
  27602. END_OF_FILE
  27603. if test 1541 -ne `wc -c <'testpad.c'`; then
  27604.     echo shar: \"'testpad.c'\" unpacked with wrong size!
  27605. fi
  27606. # end of 'testpad.c'
  27607. fi
  27608. if test -f 'getpagesize.h' -a "${1}" != "-c" ; then 
  27609.   echo shar: Will not clobber existing file \"'getpagesize.h'\"
  27610. else
  27611. echo shar: Extracting \"'getpagesize.h'\" \(610 characters\)
  27612. sed "s/^X//" >'getpagesize.h' <<'END_OF_FILE'
  27613. X#ifdef BSD
  27614. X#ifndef BSD4_1
  27615. X#define HAVE_GETPAGESIZE
  27616. X#endif
  27617. X#endif
  27618. X
  27619. X#ifndef HAVE_GETPAGESIZE
  27620. X
  27621. X#ifdef VMS
  27622. X#define getpagesize() 512
  27623. X#endif
  27624. X
  27625. X#ifdef HAVE_UNISTD_H
  27626. X#include <unistd.h>
  27627. X#endif
  27628. X
  27629. X#ifdef _SC_PAGESIZE
  27630. X#define getpagesize() sysconf(_SC_PAGESIZE)
  27631. X#else
  27632. X
  27633. X#include <sys/param.h>
  27634. X
  27635. X#ifdef EXEC_PAGESIZE
  27636. X#define getpagesize() EXEC_PAGESIZE
  27637. X#else
  27638. X#ifdef NBPG
  27639. X#define getpagesize() NBPG * CLSIZE
  27640. X#ifndef CLSIZE
  27641. X#define CLSIZE 1
  27642. X#endif /* no CLSIZE */
  27643. X#else /* no NBPG */
  27644. X#define getpagesize() NBPC
  27645. X#endif /* no NBPG */
  27646. X#endif /* no EXEC_PAGESIZE */
  27647. X#endif /* no _SC_PAGESIZE */
  27648. X
  27649. X#endif /* not HAVE_GETPAGESIZE */
  27650. X
  27651. END_OF_FILE
  27652. if test 610 -ne `wc -c <'getpagesize.h'`; then
  27653.     echo shar: \"'getpagesize.h'\" unpacked with wrong size!
  27654. fi
  27655. # end of 'getpagesize.h'
  27656. fi
  27657. echo shar: End of shell archive.
  27658. exit 0
  27659.